Skip to content

Add per-player shadow direction override via set_lighting#17014

Open
sofar wants to merge 1 commit intoluanti-org:masterfrom
sofar:sofar/shadow_direction
Open

Add per-player shadow direction override via set_lighting#17014
sofar wants to merge 1 commit intoluanti-org:masterfrom
sofar:sofar/shadow_direction

Conversation

@sofar
Copy link
Contributor

@sofar sofar commented Mar 11, 2026

Add an optional shadow.direction field to the lighting struct, allowing server mods to override the shadow light direction on a per-player basis. This is needed for games that use custom skyboxes where the sun/moon position in the skybox texture does not correspond to the engine's internal time-of-day cycle.

When shadow_direction is set, Game::updateShadows() uses it directly instead of computing direction from getSunDirection()/getMoonDirection(), and applies shadow_intensity unconditionally (bypassing the sun/moon visibility check that would otherwise zero out shadows).

Lua API:
player:set_lighting({shadows = {direction = {x=0.3, y=0.9, z=0.3}}})
player:set_lighting({shadows = {direction = false}}) -- clear override

The TOCLIENT_SET_LIGHTING packet documentation in networkprotocol.h was outdated, listing only the original fields (shadow_intensity, saturation, exposure parameters) while the actual packet has grown over several releases to include volumetric_light_strength, shadow_tint, and bloom parameters. The documentation is now updated to reflect all fields actually sent and parsed, plus the new shadow direction.

Network compatibility: the new field is appended to the end of the packet. Old clients ignore the extra bytes. New clients handle missing bytes via the existing hasRemainingBytes() pattern, falling back to sun/moon-based shadows when the server does not send a direction.

Add an optional shadow.direction field to the lighting struct, allowing
server mods to override the shadow light direction on a per-player basis.
This is needed for games that use custom skyboxes where the sun/moon
position in the skybox texture does not correspond to the engine's
internal time-of-day cycle.

When shadow_direction is set, Game::updateShadows() uses it directly
instead of computing direction from getSunDirection()/getMoonDirection(),
and applies shadow_intensity unconditionally (bypassing the sun/moon
visibility check that would otherwise zero out shadows).

Lua API:
  player:set_lighting({shadows = {direction = {x=0.3, y=0.9, z=0.3}}})
  player:set_lighting({shadows = {direction = false}})  -- clear override

The TOCLIENT_SET_LIGHTING packet documentation in networkprotocol.h was
outdated, listing only the original fields (shadow_intensity, saturation,
exposure parameters) while the actual packet has grown over several
releases to include volumetric_light_strength, shadow_tint, and bloom
parameters. The documentation is now updated to reflect all fields
actually sent and parsed, plus the new shadow direction.

Network compatibility: the new field is appended to the end of the
packet. Old clients ignore the extra bytes. New clients handle missing
bytes via the existing hasRemainingBytes() pattern, falling back to
sun/moon-based shadows when the server does not send a direction.
@sfan5 sfan5 added Feature ✨ PRs that add or enhance a feature @ Client / Audiovisuals labels Mar 11, 2026
@sfan5
Copy link
Member

sfan5 commented Mar 11, 2026

This is needed for games that use custom skyboxes where the sun/moon position in the skybox texture does not correspond to the engine's internal time-of-day cycle.

If you also want to have a different time-of-day that doesn't match the sun direction, yes.

light = is_day ? sky->getSunDirection() : sky->getMoonDirection();
}

timeoftheday = std::fmod(timeoftheday + 0.75f, 0.5f) + 0.25f;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timeoftheday is never read after this, I think it's supposed to be before the if

if (!pkt->hasRemainingBytes())
break;

u8 has_shadow_dir;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
u8 has_shadow_dir;
// >= 5.16.0-dev
u8 has_shadow_dir;

getfloatfield(L, -1, "x", dir.X);
getfloatfield(L, -1, "y", dir.Y);
getfloatfield(L, -1, "z", dir.Z);
lighting.shadow_direction = dir;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use check_v3f

lua_pushnumber(L, dir.Y);
lua_setfield(L, -2, "y");
lua_pushnumber(L, dir.Z);
lua_setfield(L, -2, "z");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

push_v3f

lua_pushnumber(L, dir.Z);
lua_setfield(L, -2, "z");
lua_setfield(L, -2, "direction");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also missing documentation for this

f32 bloom_intensity
f32 bloom_strength_factor
f32 bloom_radius
u8 has_shadow_direction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could actually skip this byte, since (0, 0, 0) can already represent "no direction"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

@ Client / Audiovisuals Feature ✨ PRs that add or enhance a feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants