Initial sanctuary sources

This commit is contained in:
cnstiout
2026-07-04 20:27:08 +02:00
commit c796a20321
1582 changed files with 253264 additions and 0 deletions
@@ -0,0 +1,208 @@
package fr.koka99cab.dynamic_torches.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.util.LightCoordsUtil;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockAndLightGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import java.util.ArrayList;
import java.util.List;
public final class DynamicTorchLights {
private static final int MAX_DYNAMIC_LIGHT = 15;
private static final int RENDER_RADIUS = MAX_DYNAMIC_LIGHT;
private static final double HAND_FORWARD_OFFSET = 0.35D;
private static final double HAND_SIDE_OFFSET = 0.35D;
private static final double HAND_DOWN_OFFSET = 0.35D;
private static ClientLevel lastLevel;
private static List<LightSource> sources = List.of();
private DynamicTorchLights() {
}
public static void tick(Minecraft client) {
if (client.level == null || client.player == null) {
sources = List.of();
lastLevel = null;
return;
}
if (client.level != lastLevel) {
sources = List.of();
lastLevel = client.level;
}
List<LightSource> nextSources = collectHeldTorchSources(client.player);
if (sameSourceBlocks(sources, nextSources)) {
sources = nextSources;
return;
}
markSourcesDirty(client.levelRenderer, sources);
sources = nextSources;
markSourcesDirty(client.levelRenderer, sources);
}
public static int applyDynamicLight(int packedLight, BlockAndLightGetter level, BlockPos pos) {
return applyDynamicLight(packedLight, pos);
}
public static int applyDynamicLight(int packedLight, BlockPos pos) {
if (sources.isEmpty() || pos == null) {
return packedLight;
}
int vanillaBlockLight = LightCoordsUtil.block(packedLight);
if (vanillaBlockLight >= 15) {
return packedLight;
}
int dynamicBlockLight = applyDynamicBlockLight(vanillaBlockLight, pos);
if (dynamicBlockLight <= vanillaBlockLight) {
return packedLight;
}
return LightCoordsUtil.withBlock(packedLight, dynamicBlockLight);
}
public static int applyDynamicBlockLight(int blockLight, BlockPos pos) {
if (sources.isEmpty() || pos == null || blockLight >= 15) {
return blockLight;
}
return Math.max(blockLight, getDynamicBlockLight(pos));
}
public static int applyHeldTorchLight(int packedLight) {
if (sources.isEmpty()) {
return packedLight;
}
int vanillaBlockLight = LightCoordsUtil.block(packedLight);
if (vanillaBlockLight >= 15) {
return packedLight;
}
int heldLight = 0;
for (LightSource source : sources) {
heldLight = Math.max(heldLight, source.lightLevel());
}
if (heldLight <= vanillaBlockLight) {
return packedLight;
}
return LightCoordsUtil.withBlock(packedLight, heldLight);
}
private static List<LightSource> collectHeldTorchSources(LocalPlayer player) {
List<LightSource> nextSources = new ArrayList<>(2);
addHandSource(player, InteractionHand.MAIN_HAND, nextSources);
addHandSource(player, InteractionHand.OFF_HAND, nextSources);
return List.copyOf(nextSources);
}
private static void addHandSource(LocalPlayer player, InteractionHand hand, List<LightSource> nextSources) {
int lightLevel = getHeldLightLevel(player.getItemInHand(hand));
if (lightLevel <= 0) {
return;
}
HumanoidArm arm = hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite();
nextSources.add(new LightSource(handPosition(player, arm), lightLevel));
}
private static int getHeldLightLevel(ItemStack stack) {
if (stack.isEmpty()) {
return 0;
}
Item item = stack.getItem();
if (item instanceof BlockItem blockItem) {
BlockState blockState = blockItem.getBlock().defaultBlockState();
return Math.min(MAX_DYNAMIC_LIGHT, Math.max(0, blockState.getLightEmission()));
}
return 0;
}
private static Vec3 handPosition(LocalPlayer player, HumanoidArm arm) {
Vec3 forward = Vec3.directionFromRotation(0.0F, player.getYRot());
Vec3 right = Vec3.directionFromRotation(0.0F, player.getYRot() + 90.0F);
double sideOffset = arm == HumanoidArm.RIGHT ? HAND_SIDE_OFFSET : -HAND_SIDE_OFFSET;
return player.getEyePosition()
.add(forward.scale(HAND_FORWARD_OFFSET))
.add(right.scale(sideOffset))
.add(0.0D, -HAND_DOWN_OFFSET, 0.0D);
}
private static int getDynamicBlockLight(BlockPos pos) {
Vec3 blockCenter = pos.getCenter();
int bestLight = 0;
for (LightSource source : sources) {
double distance = source.position().distanceTo(blockCenter);
if (distance >= source.lightLevel()) {
continue;
}
int light = Math.max(0, source.lightLevel() - (int) Math.floor(distance));
if (light > bestLight) {
bestLight = light;
}
}
return Math.min(MAX_DYNAMIC_LIGHT, bestLight);
}
private static boolean sameSourceBlocks(List<LightSource> previous, List<LightSource> next) {
if (previous.size() != next.size()) {
return false;
}
for (int i = 0; i < previous.size(); i++) {
LightSource previousSource = previous.get(i);
LightSource nextSource = next.get(i);
if (previousSource.lightLevel() != nextSource.lightLevel()) {
return false;
}
if (!BlockPos.containing(previousSource.position()).equals(BlockPos.containing(nextSource.position()))) {
return false;
}
}
return true;
}
private static void markSourcesDirty(LevelRenderer levelRenderer, List<LightSource> dirtySources) {
for (LightSource source : dirtySources) {
markSourceDirty(levelRenderer, source);
}
}
private static void markSourceDirty(LevelRenderer levelRenderer, LightSource source) {
BlockPos center = BlockPos.containing(source.position());
int radius = Math.max(RENDER_RADIUS, source.lightLevel());
int minSectionX = SectionPos.blockToSectionCoord(center.getX() - radius);
int minSectionY = SectionPos.blockToSectionCoord(center.getY() - radius);
int minSectionZ = SectionPos.blockToSectionCoord(center.getZ() - radius);
int maxSectionX = SectionPos.blockToSectionCoord(center.getX() + radius);
int maxSectionY = SectionPos.blockToSectionCoord(center.getY() + radius);
int maxSectionZ = SectionPos.blockToSectionCoord(center.getZ() + radius);
levelRenderer.setSectionRangeDirty(minSectionX, minSectionY, minSectionZ, maxSectionX, maxSectionY, maxSectionZ);
}
private record LightSource(Vec3 position, int lightLevel) {
}
}
@@ -0,0 +1,13 @@
package fr.koka99cab.dynamic_torches.client;
import fr.koka99cab.dynamic_torches.DynamicTorchesMod;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
public class DynamicTorchesClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
ClientTickEvents.END_CLIENT_TICK.register(DynamicTorchLights::tick);
DynamicTorchesMod.LOGGER.info("Dynamic Torches client initialise.");
}
}
@@ -0,0 +1,18 @@
package fr.koka99cab.dynamic_torches.mixin.client;
import fr.koka99cab.dynamic_torches.client.DynamicTorchLights;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(EntityRenderer.class)
public abstract class EntityRendererMixin {
@Inject(method = "getBlockLightLevel", at = @At("RETURN"), cancellable = true)
private void dynamicTorches$applyEntityLight(Entity entity, BlockPos pos, CallbackInfoReturnable<Integer> cir) {
cir.setReturnValue(DynamicTorchLights.applyDynamicBlockLight(cir.getReturnValue(), pos));
}
}
@@ -0,0 +1,22 @@
package fr.koka99cab.dynamic_torches.mixin.client;
import fr.koka99cab.dynamic_torches.client.DynamicTorchLights;
import net.minecraft.client.renderer.ItemInHandRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(ItemInHandRenderer.class)
public abstract class ItemInHandRendererMixin {
@ModifyArg(
method = "renderHandsWithItems",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;renderArmWithItem(Lnet/minecraft/client/player/AbstractClientPlayer;FFLnet/minecraft/world/InteractionHand;FLnet/minecraft/world/item/ItemStack;FLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;I)V"
),
index = 9
)
private int dynamicTorches$applyHeldTorchLightToHand(int light) {
return DynamicTorchLights.applyHeldTorchLight(light);
}
}
@@ -0,0 +1,24 @@
package fr.koka99cab.dynamic_torches.mixin.client;
import fr.koka99cab.dynamic_torches.client.DynamicTorchLights;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndLightGetter;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(LevelRenderer.class)
public abstract class LevelRendererMixin {
@Inject(
method = "getLightCoords(Lnet/minecraft/client/renderer/LevelRenderer$BrightnessGetter;Lnet/minecraft/world/level/BlockAndLightGetter;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;)I",
at = @At("RETURN"),
cancellable = true
)
private static void dynamicTorches$applyHeldTorchLight(LevelRenderer.BrightnessGetter brightnessGetter, BlockAndLightGetter level,
BlockState state, BlockPos pos, CallbackInfoReturnable<Integer> cir) {
cir.setReturnValue(DynamicTorchLights.applyDynamicLight(cir.getReturnValue(), level, pos));
}
}
@@ -0,0 +1,14 @@
{
"required": true,
"minVersion": "0.8",
"package": "fr.koka99cab.dynamic_torches.mixin.client",
"compatibilityLevel": "JAVA_25",
"client": [
"EntityRendererMixin",
"ItemInHandRendererMixin",
"LevelRendererMixin"
],
"injectors": {
"defaultRequire": 1
}
}
@@ -0,0 +1,15 @@
package fr.koka99cab.dynamic_torches;
import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DynamicTorchesMod implements ModInitializer {
public static final String MOD_ID = "dynamic_torches";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
@Override
public void onInitialize() {
LOGGER.info("Dynamic Torches charge pour Minecraft 26.1.2.");
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

@@ -0,0 +1,3 @@
{
"modmenu.descriptionTranslation.dynamic_torches": "Client-side dynamic lighting for luminous items held in either hand."
}
@@ -0,0 +1,3 @@
{
"modmenu.descriptionTranslation.dynamic_torches": "Lumiere dynamique cote client pour les objets lumineux tenus en main gauche ou droite."
}
@@ -0,0 +1,30 @@
{
"schemaVersion": 1,
"id": "dynamic_torches",
"version": "${version}",
"name": "Dynamic Torches",
"description": "Client-side dynamic lighting for luminous items held in either hand.",
"authors": [
"KOKA99CAB"
],
"icon": "assets/dynamic_torches/icon.png",
"license": "LGPL-3.0-or-later",
"environment": "*",
"entrypoints": {
"main": [
"fr.koka99cab.dynamic_torches.DynamicTorchesMod"
],
"client": [
"fr.koka99cab.dynamic_torches.client.DynamicTorchesClient"
]
},
"mixins": [
"dynamic_torches.client.mixins.json"
],
"depends": {
"fabricloader": ">=0.19.2",
"minecraft": "~26.1.2",
"java": ">=25",
"fabric-api": "*"
}
}