1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-08-11 17:51:04 +00:00

Add minetest.get_artificial_light and minetest.get_natural_light (#5680)

Add more detailed light detection functions, a function to get the artificial light (torches) and a function to get the sunlight as seen by the player (you can specify timeofday).

Co-authored-by: rubenwardy <rw@rubenwardy.com>
This commit is contained in:
HybridDog 2020-10-06 20:49:46 +02:00 committed by GitHub
parent e80fc22dd9
commit 2f4037752b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 180 additions and 0 deletions

View file

@ -407,6 +407,46 @@ int ModApiEnvMod::l_get_node_light(lua_State *L)
return 1;
}
// get_natural_light(pos, timeofday)
// pos = {x=num, y=num, z=num}
// timeofday: nil = current time, 0 = night, 0.5 = day
int ModApiEnvMod::l_get_natural_light(lua_State *L)
{
GET_ENV_PTR;
v3s16 pos = read_v3s16(L, 1);
bool is_position_ok;
MapNode n = env->getMap().getNode(pos, &is_position_ok);
if (!is_position_ok)
return 0;
// If the daylight is 0, nothing needs to be calculated
u8 daylight = n.param1 & 0x0f;
if (daylight == 0) {
lua_pushinteger(L, 0);
return 1;
}
u32 time_of_day;
if (lua_isnumber(L, 2)) {
time_of_day = 24000.0 * lua_tonumber(L, 2);
time_of_day %= 24000;
} else {
time_of_day = env->getTimeOfDay();
}
u32 dnr = time_to_daynight_ratio(time_of_day, true);
// If it's the same as the artificial light, the sunlight needs to be
// searched for because the value may not emanate from the sun
if (daylight == n.param1 >> 4)
daylight = env->findSunlight(pos);
lua_pushinteger(L, dnr * daylight / 1000);
return 1;
}
// place_node(pos, node)
// pos = {x=num, y=num, z=num}
int ModApiEnvMod::l_place_node(lua_State *L)
@ -1358,6 +1398,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
API_FCT(get_node);
API_FCT(get_node_or_nil);
API_FCT(get_node_light);
API_FCT(get_natural_light);
API_FCT(place_node);
API_FCT(dig_node);
API_FCT(punch_node);

View file

@ -56,6 +56,11 @@ private:
// timeofday: nil = current time, 0 = night, 0.5 = day
static int l_get_node_light(lua_State *L);
// get_natural_light(pos, timeofday)
// pos = {x=num, y=num, z=num}
// timeofday: nil = current time, 0 = night, 0.5 = day
static int l_get_natural_light(lua_State *L);
// place_node(pos, node)
// pos = {x=num, y=num, z=num}
static int l_place_node(lua_State *L);

View file

@ -1066,6 +1066,91 @@ bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
return true;
}
u8 ServerEnvironment::findSunlight(v3s16 pos) const
{
// Directions for neighbouring nodes with specified order
static const v3s16 dirs[] = {
v3s16(-1, 0, 0), v3s16(1, 0, 0), v3s16(0, 0, -1), v3s16(0, 0, 1),
v3s16(0, -1, 0), v3s16(0, 1, 0)
};
const NodeDefManager *ndef = m_server->ndef();
// found_light remembers the highest known sunlight value at pos
u8 found_light = 0;
struct stack_entry {
v3s16 pos;
s16 dist;
};
std::stack<stack_entry> stack;
stack.push({pos, 0});
std::unordered_map<s64, s8> dists;
dists[MapDatabase::getBlockAsInteger(pos)] = 0;
while (!stack.empty()) {
struct stack_entry e = stack.top();
stack.pop();
v3s16 currentPos = e.pos;
s8 dist = e.dist + 1;
for (const v3s16& off : dirs) {
v3s16 neighborPos = currentPos + off;
s64 neighborHash = MapDatabase::getBlockAsInteger(neighborPos);
// Do not walk neighborPos multiple times unless the distance to the start
// position is shorter
auto it = dists.find(neighborHash);
if (it != dists.end() && dist >= it->second)
continue;
// Position to walk
bool is_position_ok;
MapNode node = m_map->getNode(neighborPos, &is_position_ok);
if (!is_position_ok) {
// This happens very rarely because the map at currentPos is loaded
m_map->emergeBlock(neighborPos, false);
node = m_map->getNode(neighborPos, &is_position_ok);
if (!is_position_ok)
continue; // not generated
}
const ContentFeatures &def = ndef->get(node);
if (!def.sunlight_propagates) {
// Do not test propagation here again
dists[neighborHash] = -1;
continue;
}
// Sunlight could have come from here
dists[neighborHash] = dist;
u8 daylight = node.param1 & 0x0f;
// In the special case where sunlight shines from above and thus
// does not decrease with upwards distance, daylight is always
// bigger than nightlight, which never reaches 15
int possible_finlight = daylight - dist;
if (possible_finlight <= found_light) {
// Light from here cannot make a brighter light at currentPos than
// found_light
continue;
}
u8 nightlight = node.param1 >> 4;
if (daylight > nightlight) {
// Found a valid daylight
found_light = possible_finlight;
} else {
// Sunlight may be darker, so walk the neighbours
stack.push({neighborPos, dist});
}
}
}
return found_light;
}
void ServerEnvironment::clearObjects(ClearObjectsMode mode)
{
infostream << "ServerEnvironment::clearObjects(): "

View file

@ -322,6 +322,9 @@ public:
bool removeNode(v3s16 p);
bool swapNode(v3s16 p, const MapNode &n);
// Find the daylight value at pos with a Depth First Search
u8 findSunlight(v3s16 pos) const;
// Find all active objects inside a radius around a point
void getObjectsInsideRadius(std::vector<ServerActiveObject *> &objects, const v3f &pos, float radius,
std::function<bool(ServerActiveObject *obj)> include_obj_cb)