Skip to content

Instantly share code, notes, and snippets.

@UpcraftLP
Created September 29, 2019 21:26
Show Gist options
  • Save UpcraftLP/93db478535cb3954cc9f3dc98bac91cf to your computer and use it in GitHub Desktop.
Save UpcraftLP/93db478535cb3954cc9f3dc98bac91cf to your computer and use it in GitHub Desktop.
attempt on a simple dynamic lights implementation. Not tested on servers, but should work fine for SinglePlayer.
package com.github.glasspane.dynlight;
import net.fabricmc.fabric.api.tag.TagRegistry;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import java.util.stream.StreamSupport;
/**
* @author UpcraftLP
*/
public class DynLight {
public static final String MODID = "dynlight";
public static final int TORCH_LIGHT_LEVEL = 14;
private static final Tag<Item> Light_SOURCES = TagRegistry.item(new Identifier(MODID, "light_sources"));
public static boolean checkDistance(PlayerEntity player, BlockPos pos) {
return pos.equals(player.getBlockPos()) && isHoldingLightSource(player);
}
public static boolean isHoldingLightSource(PlayerEntity player) {
return StreamSupport.stream(player.getItemsHand().spliterator(), false).anyMatch(itemStack -> itemStack.getItem().isIn(Light_SOURCES));
}
}
{
"replace": false,
"values": [
"minecraft:beacon",
"minecraft:campfire",
"minecraft:end_rod",
"minecraft:glowstone",
"minecraft:jack_o_lantern",
"minecraft:lantern",
"minecraft:lava_bucket",
"minecraft:torch"
]
}
package com.github.glasspane.dynlight.mixin;
import com.github.glasspane.dynlight.DynLight;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.recipe.book.ClientRecipeBook;
import net.minecraft.client.util.ClientPlayerTickable;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.stat.StatHandler;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
/**
* @author UpcraftLP
*/
@Mixin(ClientPlayerEntity.class)
public class MixinClientPlayerEntity extends AbstractClientPlayerEntity {
@Shadow
@Final
private List<ClientPlayerTickable> tickables;
private boolean dynlight_wasHoldingLastTick = false;
public MixinClientPlayerEntity(ClientWorld world, GameProfile gameProfile) {
super(world, gameProfile);
}
@Inject(method = "<init>", at = @At("RETURN"))
private void construct(MinecraftClient client, ClientWorld world, ClientPlayNetworkHandler networkHandler, StatHandler statHandler, ClientRecipeBook recipeBook, CallbackInfo ci) {
this.tickables.add(() -> {
boolean hasLight = DynLight.isHoldingLightSource(this);
if(hasLight || dynlight_wasHoldingLastTick) { //only queue light updates if we are actually holding a light source
this.world.getProfiler().push("queueCheckLight");
BlockPos.iterate(this.getBlockPos().add(-1, -1, -1), this.getBlockPos().add(1, 2, 1)).forEach(this.world.getChunkManager().getLightingProvider()::enqueueLightUpdate);
this.world.getProfiler().pop();
dynlight_wasHoldingLastTick = hasLight;
}
});
}
}
{
"required": true,
"minVersion": "0.7.11",
"package": "com.github.glasspane.dynlight.mixin",
"compatibilityLevel": "JAVA_8",
"client": [
"MixinClientPlayerEntity",
"MixinServerLightingProvider",
"MixinWorldChunk"
],
"injectors": {
"defaultRequire": 1
}
}
package com.github.glasspane.dynlight.mixin;
import com.github.glasspane.dynlight.DynLight;
import net.minecraft.client.MinecraftClient;
import net.minecraft.server.world.ServerLightingProvider;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.ChunkProvider;
import net.minecraft.world.chunk.light.LightingProvider;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
/**
* @author UpcraftLP
*/
@Mixin(ServerLightingProvider.class)
public abstract class MixinServerLightingProvider extends LightingProvider {
public MixinServerLightingProvider(ChunkProvider chunkProvider_1, boolean boolean_1, boolean boolean_2) {
super(chunkProvider_1, boolean_1, boolean_2);
}
@SuppressWarnings("UnresolvedMixinReference")
@ModifyArg(method = "method_14275", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/light/LightingProvider;method_15560(Lnet/minecraft/util/math/BlockPos;I)V"))
private int getLuminance(BlockPos pos, int luminanceIn) {
if(DynLight.checkDistance(MinecraftClient.getInstance().player, pos)) {
return DynLight.TORCH_LIGHT_LEVEL;
}
return luminanceIn;
}
}
package com.github.glasspane.dynlight.mixin;
import com.github.glasspane.dynlight.DynLight;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.WorldChunk;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.function.Predicate;
/**
* @author UpcraftLP
*/
@Mixin(WorldChunk.class)
public abstract class MixinWorldChunk implements Chunk {
@ModifyArg(method = "getLightSourcesStream", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;filter(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;"))
private Predicate<BlockPos> getLightSources(Predicate<BlockPos> predicate) {
PlayerEntity player = MinecraftClient.getInstance().player;
return predicate.or(pos -> DynLight.checkDistance(player, pos));
} @Shadow
public abstract BlockState getBlockState(BlockPos blockPos_1);
@Override
public int getLuminance(BlockPos pos) {
return DynLight.checkDistance(MinecraftClient.getInstance().player, pos) ? DynLight.TORCH_LIGHT_LEVEL : this.getBlockState(pos).getLuminance();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment