diff --git a/common/src/main/java/dev/schmarrn/lighty/Lighty.java b/common/src/main/java/dev/schmarrn/lighty/Lighty.java index ecc1d7f..591515b 100644 --- a/common/src/main/java/dev/schmarrn/lighty/Lighty.java +++ b/common/src/main/java/dev/schmarrn/lighty/Lighty.java @@ -18,6 +18,7 @@ import dev.schmarrn.lighty.event.KeyBind; import dev.schmarrn.lighty.mode.BoringCrossMode; import dev.schmarrn.lighty.mode.CarpetMode; +import dev.schmarrn.lighty.mode.FarmlandMode; import dev.schmarrn.lighty.mode.NumberMode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +36,7 @@ public static void init() { CarpetMode.init(); NumberMode.init(); BoringCrossMode.init(); + FarmlandMode.init(); KeyBind.init(); } diff --git a/common/src/main/java/dev/schmarrn/lighty/api/LightyColors.java b/common/src/main/java/dev/schmarrn/lighty/api/LightyColors.java index 87d00f0..6ab5a39 100644 --- a/common/src/main/java/dev/schmarrn/lighty/api/LightyColors.java +++ b/common/src/main/java/dev/schmarrn/lighty/api/LightyColors.java @@ -56,17 +56,22 @@ public static int getDangerARGB() { } public static int getARGB(int blockLightLevel, int skyLightLevel) { - int color = LightyColors.getSafeARGB(); - - if (blockLightLevel <= Config.getBlockThreshold()) { - if (skyLightLevel <= Config.getSkyThreshold()) { - color = LightyColors.getDangerARGB(); - } else { - color = LightyColors.getWarningARGB(); - } - } + // Artificial light is always safe + if (blockLightLevel > Config.getBlockThreshold()) return LightyColors.getSafeARGB(); + // If we don't have artificial lighting, mobs can spawn at night + if (skyLightLevel > Config.getSkyThreshold()) return LightyColors.getWarningARGB(); + // Without artificial nor skylight, mobs can always spawn + return LightyColors.getDangerARGB(); + } - return color; + public static int getGrowthARGB(int blockLightLevel, int skyLightLevel) { + int internalLightLevel = Integer.max(blockLightLevel, skyLightLevel); + // Above the growth threshold crops always grow + if (internalLightLevel > Config.getFarmGrowthThreshold()) return LightyColors.getSafeARGB(); + // Crops can be planted but won't grow without additional light + if (internalLightLevel < Config.getFarmUprootThreshold()) return LightyColors.getWarningARGB(); + // There is insufficient light here; crops will uproot themselves and can't be planted + return LightyColors.getDangerARGB(); } private LightyColors() {} diff --git a/common/src/main/java/dev/schmarrn/lighty/api/LightyHelper.java b/common/src/main/java/dev/schmarrn/lighty/api/LightyHelper.java index d6d8c48..75ff827 100644 --- a/common/src/main/java/dev/schmarrn/lighty/api/LightyHelper.java +++ b/common/src/main/java/dev/schmarrn/lighty/api/LightyHelper.java @@ -29,30 +29,42 @@ private static boolean specialCases(Block block) { return block instanceof CarpetBlock; } - public static float getOffset(BlockState block, BlockPos pos, ClientLevel world) { - float offset = 0; - if (block.getBlock() instanceof SnowLayerBlock) { // snow layers - int layer = world.getBlockState(pos).getValue(SnowLayerBlock.LAYERS); + public static float getOffset(BlockState blockState, BlockPos pos, ClientLevel world) { + // Returns the offset of blocks that aren't 16 pixels high, for example snow layers or farmland. + + Block block = blockState.getBlock(); + if (block instanceof FarmBlock) { // farmland + // FarmBlocks are 15 pixels high + return -1f/16f; + } + + BlockState blockStateUp = world.getBlockState(pos.above()); + Block blockUp = blockStateUp.getBlock(); + if (blockUp instanceof SnowLayerBlock) { // snow layers + int layer = blockStateUp.getValue(SnowLayerBlock.LAYERS); if (layer != 1) { // Mobs cannot spawn on those blocks return -1; } // One layer of snow is two pixels high, with one pixel being 1/16 - offset = 2f / 16f * layer; + return 2f / 16f * layer; } - return offset; + + return 0f; } - public static boolean isBlocked(BlockState block, BlockState up, ClientLevel world, BlockPos pos, BlockPos upPos) { + public static boolean isBlocked(BlockState block, BlockPos pos, ClientLevel world) { + BlockPos posUp = pos.above(); + BlockState blockStateUp = world.getBlockState(posUp); // Resource: https://minecraft.fandom.com/wiki/Tutorials/Spawn-proofing - return (up.isCollisionShapeFullBlock(world, upPos) || // Full blocks are not spawnable in + return (blockStateUp.isCollisionShapeFullBlock(world, posUp) || // Full blocks are not spawnable in !block.isFaceSturdy(world, pos, Direction.UP) || // Block below needs to be sturdy - isRedstone(up.getBlock()) || // Mobs don't spawn in redstone - specialCases(up.getBlock()) || // Carpets and snow + isRedstone(blockStateUp.getBlock()) || // Mobs don't spawn in redstone + specialCases(blockStateUp.getBlock()) || // Carpets and snow !protectedIsValidSpawnCheck(block, pos, world) || // use minecraft internal isValidSpawn check - !up.getFluidState().isEmpty()) || // don't spawn in fluidlogged stuff (Kelp, Seagrass, Growlichen) - !up.getBlock().isPossibleToRespawnInThis(up) || - up.is(BlockTags.PREVENT_MOB_SPAWNING_INSIDE); // As of 1.20.1, only contains rails, don't know if it is even really available on the client + !blockStateUp.getFluidState().isEmpty()) || // don't spawn in fluidlogged stuff (Kelp, Seagrass, Growlichen) + !blockStateUp.getBlock().isPossibleToRespawnInThis(blockStateUp) || + blockStateUp.is(BlockTags.PREVENT_MOB_SPAWNING_INSIDE); // As of 1.20.1, only contains rails, don't know if it is even really available on the client } public static boolean isSafe(int blockLightLevel) { diff --git a/common/src/main/java/dev/schmarrn/lighty/config/Config.java b/common/src/main/java/dev/schmarrn/lighty/config/Config.java index 6d5952b..01cd740 100644 --- a/common/src/main/java/dev/schmarrn/lighty/config/Config.java +++ b/common/src/main/java/dev/schmarrn/lighty/config/Config.java @@ -32,6 +32,8 @@ public class Config { private static final String LAST_USED_MODE = "lighty.last_used_mode"; private static final String SKY_THRESHOLD = "lighty.sky_threshold"; private static final String BLOCK_THRESHOLD = "lighty.block_threshold"; + private static final String FARM_GROWTH_THRESHOLD = "lighty.farm_growth_threshold"; + private static final String FARM_UPROOT_THRESHOLD = "lighty.farm_uproot_threshold"; private static final String OVERLAY_DISTANCE = "lighty.overlay_distance"; private static final String OVERLAY_BRIGHTNESS = "lighty.overlay_brightness"; private static final String SHOW_SAFE = "lighty.show_safe"; @@ -50,6 +52,8 @@ private Config() { properties.putIfAbsent(LAST_USED_MODE, "lighty:carpet_mode"); properties.putIfAbsent(SKY_THRESHOLD, "0"); properties.putIfAbsent(BLOCK_THRESHOLD, "0"); + properties.putIfAbsent(FARM_GROWTH_THRESHOLD, "8"); + properties.putIfAbsent(FARM_UPROOT_THRESHOLD, "8"); properties.putIfAbsent(OVERLAY_DISTANCE, "2"); properties.putIfAbsent(OVERLAY_BRIGHTNESS, "10"); properties.putIfAbsent(SHOW_SAFE, String.valueOf(true)); @@ -63,6 +67,8 @@ private Config() { properties.setProperty(LAST_USED_MODE, "lighty:carpet_mode"); properties.setProperty(SKY_THRESHOLD, "0"); properties.setProperty(BLOCK_THRESHOLD, "0"); + properties.setProperty(FARM_GROWTH_THRESHOLD, "8"); + properties.setProperty(FARM_UPROOT_THRESHOLD, "8"); properties.setProperty(OVERLAY_DISTANCE, "2"); properties.setProperty(OVERLAY_BRIGHTNESS, "10"); properties.setProperty(SHOW_SAFE, String.valueOf(true)); @@ -93,6 +99,14 @@ public static int getBlockThreshold() { return Integer.parseInt(config.properties.getProperty(BLOCK_THRESHOLD, "0")); } + public static int getFarmGrowthThreshold() { + return Integer.parseInt(config.properties.getProperty(FARM_GROWTH_THRESHOLD, "8")); + } + + public static int getFarmUprootThreshold() { + return Integer.parseInt(config.properties.getProperty(FARM_UPROOT_THRESHOLD, "8")); + } + public static int getOverlayDistance() { return Integer.parseInt(config.properties.getProperty(OVERLAY_DISTANCE, "2")); } @@ -123,6 +137,16 @@ public static void setBlockThreshold(int i) { config.write(); } + public static void setFarmGrowthThreshold(int i) { + config.properties.setProperty(FARM_GROWTH_THRESHOLD, String.valueOf(i)); + config.write(); + } + + public static void setFarmUprootThreshold(int i) { + config.properties.setProperty(FARM_UPROOT_THRESHOLD, String.valueOf(i)); + config.write(); + } + public static void setOverlayDistance(int i) { config.properties.setProperty(OVERLAY_DISTANCE, String.valueOf(i)); config.write(); diff --git a/common/src/main/java/dev/schmarrn/lighty/mode/BoringCrossMode.java b/common/src/main/java/dev/schmarrn/lighty/mode/BoringCrossMode.java index c0c3ea4..b6f86c3 100644 --- a/common/src/main/java/dev/schmarrn/lighty/mode/BoringCrossMode.java +++ b/common/src/main/java/dev/schmarrn/lighty/mode/BoringCrossMode.java @@ -30,6 +30,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.state.BlockState; public class BoringCrossMode extends LightyMode { @@ -40,7 +41,8 @@ public void beforeCompute(BufferBuilder builder) { @Override public void compute(ClientLevel world, BlockPos pos, BufferBuilder builder) { - if (!LightyHelper.isBlocked(world.getBlockState(pos.below()), world.getBlockState(pos), world, pos.below(), pos)) { + BlockState blockState = world.getBlockState(pos); + if (!LightyHelper.isBlocked(world.getBlockState(pos.below()), pos, world)) { int blockLightLevel = world.getBrightness(LightLayer.BLOCK, pos); int skyLightLevel = world.getBrightness(LightLayer.SKY, pos); @@ -50,7 +52,7 @@ public void compute(ClientLevel world, BlockPos pos, BufferBuilder builder) { int color = LightyColors.getARGB(blockLightLevel, skyLightLevel); - float offset = LightyHelper.getOffset(world.getBlockState(pos), pos, world); + float offset = LightyHelper.getOffset(blockState, pos, world); if (offset == -1f) { return; } diff --git a/common/src/main/java/dev/schmarrn/lighty/mode/CarpetMode.java b/common/src/main/java/dev/schmarrn/lighty/mode/CarpetMode.java index ec22c88..0f1ea04 100644 --- a/common/src/main/java/dev/schmarrn/lighty/mode/CarpetMode.java +++ b/common/src/main/java/dev/schmarrn/lighty/mode/CarpetMode.java @@ -44,10 +44,9 @@ public void beforeCompute(BufferBuilder builder) { @Override public void compute(ClientLevel world, BlockPos pos, BufferBuilder builder) { BlockPos posUp = pos.above(); - BlockState up = world.getBlockState(posUp); - BlockState block = world.getBlockState(pos); + BlockState blockState = world.getBlockState(pos); - if (LightyHelper.isBlocked(block, up, world, pos, posUp)) { + if (LightyHelper.isBlocked(blockState, pos, world)) { return; } @@ -60,8 +59,7 @@ public void compute(ClientLevel world, BlockPos pos, BufferBuilder builder) { int color = LightyColors.getARGB(blockLightLevel, skyLightLevel); - double offset = LightyHelper.getOffset(up, posUp, world); - + double offset = LightyHelper.getOffset(blockState, pos, world); if (offset == -1f) { return; } diff --git a/common/src/main/java/dev/schmarrn/lighty/mode/FarmlandMode.java b/common/src/main/java/dev/schmarrn/lighty/mode/FarmlandMode.java new file mode 100644 index 0000000..7b04e7a --- /dev/null +++ b/common/src/main/java/dev/schmarrn/lighty/mode/FarmlandMode.java @@ -0,0 +1,90 @@ +package dev.schmarrn.lighty.mode; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import dev.schmarrn.lighty.Lighty; +import dev.schmarrn.lighty.api.LightyColors; +import dev.schmarrn.lighty.api.LightyHelper; +import dev.schmarrn.lighty.api.ModeManager; +import dev.schmarrn.lighty.config.Config; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.FarmBlock; +import net.minecraft.world.level.block.state.BlockState; + +/** + * Extending CarpetMode because the code is largely identical + */ +public class FarmlandMode extends CarpetMode { + @Override + public void compute(ClientLevel world, BlockPos pos, BufferBuilder builder) { + BlockPos posUp = pos.above(); + BlockState blockState = world.getBlockState(pos); + + if (!(blockState.getBlock() instanceof FarmBlock)) { + return; + } + + int blockLightLevel = world.getBrightness(LightLayer.BLOCK, posUp); + int skyLightLevel = world.getBrightness(LightLayer.SKY, posUp); + int color = LightyColors.getGrowthARGB(blockLightLevel, skyLightLevel); + + double offset = LightyHelper.getOffset(blockState, pos, world); + if (offset == -1f) { + return; + } + + double x = pos.getX(); + double y = pos.getY() + 1 + offset; + double z = pos.getZ(); + int overlayBrightness = Config.getOverlayBrightness(); + // the first parameter corresponds to the blockLightLevel, the second to the skyLightLevel + int lightmap = LightTexture.pack(overlayBrightness, overlayBrightness); + //TOP + builder.vertex(x, y + 1 / 16f, z).color(color).uv(0, 0).uv2(lightmap).normal(0f, 1f, 0f).endVertex(); + builder.vertex(x, y + 1 / 16f, z + 1).color(color).uv(0, 1).uv2(lightmap).normal(0f, 1f, 0f).endVertex(); + builder.vertex(x + 1, y + 1 / 16f, z + 1).color(color).uv(1, 1).uv2(lightmap).normal(0f, 1f, 0f).endVertex(); + builder.vertex(x + 1, y + 1 / 16f, z).color(color).uv(1, 0).uv2(lightmap).normal(0f, 1f, 0f).endVertex(); + if (offset > 0.001f) { + //if it renders above it should check if the block above culls the faces + pos = pos.above(); + } + //NORTH + if (Block.shouldRenderFace(Blocks.STONE.defaultBlockState(), world, pos, Direction.SOUTH, pos.relative(Direction.SOUTH))) { + builder.vertex(x, y + 1 / 16f, z + 1).color(color).uv(0, 1f / 16).uv2(lightmap).normal(0f, 0f, -1f).endVertex(); + builder.vertex(x, y, z + 1).color(color).uv(0, 0).uv2(lightmap).normal(0f, 0f, -1f).endVertex(); + builder.vertex(x + 1, y, z + 1).color(color).uv(1, 0).uv2(lightmap).normal(0f, 0f, -1f).endVertex(); + builder.vertex(x + 1, y + 1 / 16f, z + 1).color(color).uv(1, 1f / 16).uv2(lightmap).normal(0f, 0f, -1f).endVertex(); + } + //EAST + if (Block.shouldRenderFace(Blocks.STONE.defaultBlockState(), world, pos, Direction.WEST, pos.relative(Direction.WEST))) { + builder.vertex(x, y + 1/16f, z).color(color).uv(0,1f/16).uv2(lightmap).normal(-1f, 0f, 0f).endVertex(); + builder.vertex(x, y, z).color(color).uv(0, 0).uv2(lightmap).normal(-1f, 0f, 0f).endVertex(); + builder.vertex(x, y, z + 1).color(color).uv(1, 0).uv2(lightmap).normal(-1f, 0f, 0f).endVertex(); + builder.vertex(x, y + 1/16f, z + 1).color(color).uv(1, 1f/16).uv2(lightmap).normal(-1f, 0f, 0f).endVertex(); + } + //SOUTH + if (Block.shouldRenderFace(Blocks.STONE.defaultBlockState(), world, pos, Direction.NORTH, pos.relative(Direction.NORTH))) { + builder.vertex(x+1, y + 1/16f, z).color(color).uv(0,1f/16).uv2(lightmap).normal(0f, 0f, 1f).endVertex(); + builder.vertex(x+1, y, z).color(color).uv(0, 0).uv2(lightmap).normal(0f, 0f, -1f).endVertex(); + builder.vertex(x, y, z).color(color).uv(1, 0).uv2(lightmap).normal(0f, 0f, -1f).endVertex(); + builder.vertex(x, y + 1/16f, z).color(color).uv(1, 1f/16).uv2(lightmap).normal(0f, 0f, -1f).endVertex(); + } + //WEST + if (Block.shouldRenderFace(Blocks.STONE.defaultBlockState(), world, pos, Direction.EAST, pos.relative(Direction.EAST))) { + builder.vertex(x+1, y + 1/16f, z+1).color(color).uv(0,1f/16).uv2(lightmap).normal(1f, 0f, 0f).endVertex(); + builder.vertex(x+1, y, z+1).color(color).uv(0, 0).uv2(lightmap).normal(1f, 0f, 0f).endVertex(); + builder.vertex(x+1, y, z).color(color).uv(1, 0).uv2(lightmap).normal(1f, 0f, 0f).endVertex(); + builder.vertex(x+1, y + 1/16f, z).color(color).uv(1, 1f/16).uv2(lightmap).normal(1f, 0f, 0f).endVertex(); + } + } + + public static void init() { + ModeManager.registerMode(new ResourceLocation(Lighty.MOD_ID, "farmland_mode"), new FarmlandMode()); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/schmarrn/lighty/mode/NumberMode.java b/common/src/main/java/dev/schmarrn/lighty/mode/NumberMode.java index 0797085..9c8d71d 100644 --- a/common/src/main/java/dev/schmarrn/lighty/mode/NumberMode.java +++ b/common/src/main/java/dev/schmarrn/lighty/mode/NumberMode.java @@ -87,9 +87,8 @@ private static void renderNumber(BufferBuilder builder, int number, float x, flo @Override public void compute(ClientLevel world, BlockPos pos, BufferBuilder builder) { BlockPos posUp = pos.above(); - BlockState up = world.getBlockState(posUp); - BlockState block = world.getBlockState(pos); - if (LightyHelper.isBlocked(block, up, world, pos, posUp)) { + BlockState blockState = world.getBlockState(pos); + if (LightyHelper.isBlocked(blockState, pos, world)) { return; } @@ -102,7 +101,7 @@ public void compute(ClientLevel world, BlockPos pos, BufferBuilder builder) { int color = LightyColors.getARGB(blockLightLevel, skyLightLevel); - float offset = LightyHelper.getOffset(up, posUp, world); + float offset = LightyHelper.getOffset(blockState, pos, world); if (offset == -1f) { return; } diff --git a/common/src/main/java/dev/schmarrn/lighty/ui/SettingsScreen.java b/common/src/main/java/dev/schmarrn/lighty/ui/SettingsScreen.java index d2d7ba7..0eb0d19 100644 --- a/common/src/main/java/dev/schmarrn/lighty/ui/SettingsScreen.java +++ b/common/src/main/java/dev/schmarrn/lighty/ui/SettingsScreen.java @@ -21,7 +21,6 @@ import net.minecraft.client.Options; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.Checkbox; import net.minecraft.client.gui.components.OptionsList; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.screens.Screen; @@ -29,8 +28,6 @@ import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; - public class SettingsScreen extends Screen { public SettingsScreen() { super(Component.translatable("settings.lighty.title")); @@ -83,6 +80,24 @@ protected void init() { Config.getSkyThreshold(), Config::setSkyThreshold ), + new OptionInstance<>( + "lighty.options.farm_growth_threshold", + object -> Tooltip.create(Component.translatable("lighty.options.farm_growth_threshold.tooltip", object)), + (component, integer) -> Options.genericValueLabel(component, Component.literal(integer.toString())), + new OptionInstance.IntRange(0, 15), + Codec.intRange(0, 15), + Config.getFarmGrowthThreshold(), + Config::setFarmGrowthThreshold + ), + new OptionInstance<>( + "lighty.options.farm_uproot_threshold", + object -> Tooltip.create(Component.translatable("lighty.options.farm_uproot_threshold.tooltip", object)), + (component, integer) -> Options.genericValueLabel(component, Component.literal(integer.toString())), + new OptionInstance.IntRange(0, 15), + Codec.intRange(0, 15), + Config.getFarmUprootThreshold(), + Config::setFarmUprootThreshold + ), OptionInstance.createBoolean( "lighty.options.show_safe", object -> Tooltip.create(Component.translatable("lighty.options.show_safe.tooltip", object)), diff --git a/common/src/main/resources/assets/lighty/lang/en_us.json b/common/src/main/resources/assets/lighty/lang/en_us.json index 84f516e..21c4931 100644 --- a/common/src/main/resources/assets/lighty/lang/en_us.json +++ b/common/src/main/resources/assets/lighty/lang/en_us.json @@ -9,10 +9,16 @@ "modeSwitcher.lighty.carpet_mode.tooltip": "Original, carpet like overlay", "modeSwitcher.lighty.boring_cross_mode": "Boring Cross Mode", "modeSwitcher.lighty.boring_cross_mode.tooltip": "It feels like every Light Overlay Mod has them", + "modeSwitcher.lighty.farmland_mode": "Farmland Mode", + "modeSwitcher.lighty.farmland_mode.tooltip": "Similar to Carpet Mode but exclusively for farmland blocks", "modeSwitcher.lighty.settings": "Overlay Settings", "settings.lighty.title": "Lighty Settings", "lighty.options.block_threshold": "Block Threshold", "lighty.options.block_threshold.tooltip": "If the block light level is less than or equal to %d, the overlay is red or orange, depending on the sky light level. Otherwise, it is green.", + "lighty.options.farm_growth_threshold": "Farmland Growth Threshold", + "lighty.options.farm_growth_threshold.tooltip": "With a light level above %d, crops will grow and the overlay is green. Below, crops won't grow and the overlay is orange.", + "lighty.options.farm_uproot_threshold": "Farmland Uproot Threshold", + "lighty.options.farm_uproot_threshold.tooltip": "With a light level below %d, crops can't be planted and the overlay is red.", "lighty.options.sky_threshold": "Sky Threshold", "lighty.options.sky_threshold.tooltip": "If the block light level is below the value specified in 'Block Threshold' and the sky light level is less than or equal to %d, the overlay is red. Otherwise, it is orange.", "lighty.options.overlay_distance": "Overlay Distance",