Skip to content

Commit

Permalink
Merge pull request #55 from Alveel/light-level-for-crops
Browse files Browse the repository at this point in the history
Add new Farmland Mode with light level for crops
  • Loading branch information
andi-makes authored Apr 5, 2024
2 parents e886613 + c237a31 commit aaad716
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 37 deletions.
2 changes: 2 additions & 0 deletions common/src/main/java/dev/schmarrn/lighty/Lighty.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -35,6 +36,7 @@ public static void init() {
CarpetMode.init();
NumberMode.init();
BoringCrossMode.init();
FarmlandMode.init();
KeyBind.init();
}

Expand Down
25 changes: 15 additions & 10 deletions common/src/main/java/dev/schmarrn/lighty/api/LightyColors.java
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Expand Down
38 changes: 25 additions & 13 deletions common/src/main/java/dev/schmarrn/lighty/api/LightyHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
24 changes: 24 additions & 0 deletions common/src/main/java/dev/schmarrn/lighty/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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"));
}
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -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);

Expand All @@ -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;
}
Expand Down
8 changes: 3 additions & 5 deletions common/src/main/java/dev/schmarrn/lighty/mode/CarpetMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
}
Expand Down
90 changes: 90 additions & 0 deletions common/src/main/java/dev/schmarrn/lighty/mode/FarmlandMode.java
Original file line number Diff line number Diff line change
@@ -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());
}
}
7 changes: 3 additions & 4 deletions common/src/main/java/dev/schmarrn/lighty/mode/NumberMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
}
Expand Down
21 changes: 18 additions & 3 deletions common/src/main/java/dev/schmarrn/lighty/ui/SettingsScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,13 @@
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;
import net.minecraft.network.chat.CommonComponents;
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"));
Expand Down Expand Up @@ -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)),
Expand Down
Loading

0 comments on commit aaad716

Please sign in to comment.