Skip to content

Commit 57e5aa6

Browse files
juhdanadEkdohibs
authored andcommittedApr 20, 2017
Light update for map blocks
This is not really different from the light update of a voxel manipulator. This update does not assume that the lighting was correct before, therefore it is useful for correction. Also expose this function to the Lua API for light correction, and allow voxel manipulators not to update the light.
1 parent 6d1e6f8 commit 57e5aa6

File tree

8 files changed

+209
-3
lines changed

8 files changed

+209
-3
lines changed
 

‎doc/lua_api.txt

+23-1
Original file line numberDiff line numberDiff line change
@@ -2398,6 +2398,22 @@ and `minetest.auth_reload` call the authetification handler.
23982398
* increase level of leveled node by level, default `level` equals `1`
23992399
* if `totallevel > maxlevel`, returns rest (`total-max`)
24002400
* can be negative for decreasing
2401+
* `minetest.fix_light(pos1, pos2)`: returns `true`/`false`
2402+
* resets the light in a cuboid-shaped part of
2403+
the map and removes lighting bugs.
2404+
* Loads the area if it is not loaded.
2405+
* `pos1` is the corner of the cuboid with the least coordinates
2406+
(in node coordinates), inclusive.
2407+
* `pos2` is the opposite corner of the cuboid, inclusive.
2408+
* The actual updated cuboid might be larger than the specified one,
2409+
because only whole map blocks can be updated.
2410+
The actual updated area consists of those map blocks that intersect
2411+
with the given cuboid.
2412+
* However, the neighborhood of the updated area might change
2413+
as well, as light can spread out of the cuboid, also light
2414+
might be removed.
2415+
* returns `false` if the area is not fully generated,
2416+
`true` otherwise
24012417
* `core.check_single_for_falling(pos)`
24022418
* causes an unsupported `group:falling_node` node to fall and causes an
24032419
unattached `group:attached_node` node to fall.
@@ -3421,8 +3437,14 @@ will place the schematic inside of the VoxelManip.
34213437
* `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object containing
34223438
the region formed by `p1` and `p2`.
34233439
* returns actual emerged `pmin`, actual emerged `pmax`
3424-
* `write_to_map()`: Writes the data loaded from the `VoxelManip` back to the map.
3440+
* `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to the map.
34253441
* **important**: data must be set using `VoxelManip:set_data()` before calling this
3442+
* if `light` is true, then lighting is automatically recalculated.
3443+
The default value is true.
3444+
If `light` is false, no light calculations happen, and you should correct
3445+
all modified blocks with `minetest.fix_light()` as soon as possible.
3446+
Keep in mind that modifying the map where light is incorrect can cause
3447+
more lighting bugs.
34263448
* `get_node_at(pos)`: Returns a `MapNode` table of the node currently loaded in
34273449
the `VoxelManip` at that position
34283450
* `set_node_at(pos, node)`: Sets a specific `MapNode` in the `VoxelManip` at that position

‎src/map.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -2591,6 +2591,16 @@ void ServerMap::PrintInfo(std::ostream &out)
25912591
out<<"ServerMap: ";
25922592
}
25932593

2594+
bool ServerMap::repairBlockLight(v3s16 blockpos,
2595+
std::map<v3s16, MapBlock *> *modified_blocks)
2596+
{
2597+
MapBlock *block = emergeBlock(blockpos, false);
2598+
if (!block || !block->isGenerated())
2599+
return false;
2600+
voxalgo::repair_block_light(this, block, modified_blocks);
2601+
return true;
2602+
}
2603+
25942604
MMVManip::MMVManip(Map *map):
25952605
VoxelManipulator(),
25962606
m_is_dirty(false),

‎src/map.h

+10
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,16 @@ class ServerMap : public Map
477477
u64 getSeed();
478478
s16 getWaterLevel();
479479

480+
/*!
481+
* Fixes lighting in one map block.
482+
* May modify other blocks as well, as light can spread
483+
* out of the specified block.
484+
* Returns false if the block is not generated (so nothing
485+
* changed), true otherwise.
486+
*/
487+
bool repairBlockLight(v3s16 blockpos,
488+
std::map<v3s16, MapBlock *> *modified_blocks);
489+
480490
MapSettingsManager settings_mgr;
481491

482492
private:

‎src/script/lua_api/l_env.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,36 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L)
847847
return 1;
848848
}
849849

850+
// fix_light(p1, p2)
851+
int ModApiEnvMod::l_fix_light(lua_State *L)
852+
{
853+
GET_ENV_PTR;
854+
855+
v3s16 blockpos1 = getContainerPos(read_v3s16(L, 1), MAP_BLOCKSIZE);
856+
v3s16 blockpos2 = getContainerPos(read_v3s16(L, 2), MAP_BLOCKSIZE);
857+
ServerMap &map = env->getServerMap();
858+
std::map<v3s16, MapBlock *> modified_blocks;
859+
bool success = true;
860+
v3s16 blockpos;
861+
for (blockpos.X = blockpos1.X; blockpos.X <= blockpos2.X; blockpos.X++)
862+
for (blockpos.Y = blockpos1.Y; blockpos.Y <= blockpos2.Y; blockpos.Y++)
863+
for (blockpos.Z = blockpos1.Z; blockpos.Z <= blockpos2.Z; blockpos.Z++) {
864+
success = success & map.repairBlockLight(blockpos, &modified_blocks);
865+
}
866+
if (modified_blocks.size() > 0) {
867+
MapEditEvent event;
868+
event.type = MEET_OTHER;
869+
for (std::map<v3s16, MapBlock *>::iterator it = modified_blocks.begin();
870+
it != modified_blocks.end(); ++it)
871+
event.modified_blocks.insert(it->first);
872+
873+
map.dispatchEvent(&event);
874+
}
875+
lua_pushboolean(L, success);
876+
877+
return 1;
878+
}
879+
850880
// emerge_area(p1, p2, [callback, context])
851881
// emerge mapblocks in area p1..p2, calls callback with context upon completion
852882
int ModApiEnvMod::l_emerge_area(lua_State *L)
@@ -1089,6 +1119,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
10891119
API_FCT(find_node_near);
10901120
API_FCT(find_nodes_in_area);
10911121
API_FCT(find_nodes_in_area_under_air);
1122+
API_FCT(fix_light);
10921123
API_FCT(emerge_area);
10931124
API_FCT(delete_area);
10941125
API_FCT(get_perlin);

‎src/script/lua_api/l_env.h

+3
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class ModApiEnvMod : public ModApiBase {
128128
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
129129
static int l_find_nodes_in_area_under_air(lua_State *L);
130130

131+
// fix_light(p1, p2) -> true/false
132+
static int l_fix_light(lua_State *L);
133+
131134
// emerge_area(p1, p2)
132135
static int l_emerge_area(lua_State *L);
133136

‎src/script/lua_api/l_vmanip.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,10 @@ int LuaVoxelManip::l_write_to_map(lua_State *L)
110110
MAP_LOCK_REQUIRED;
111111

112112
LuaVoxelManip *o = checkobject(L, 1);
113+
bool update_light = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : true;
113114
GET_ENV_PTR;
114115
ServerMap *map = &(env->getServerMap());
115-
if (o->is_mapgen_vm) {
116+
if (o->is_mapgen_vm || !update_light) {
116117
o->vm->blitBackAll(&(o->modified_blocks));
117118
} else {
118119
voxalgo::blit_back_with_light(map, o->vm,

‎src/voxelalgorithms.cpp

+121-1
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,7 @@ void finish_bulk_light_update(Map *map, mapblock_v3 minblock,
11361136
for (s16 b_x = minblock.X; b_x <= maxblock.X; b_x++)
11371137
for (s16 b_y = minblock.Y; b_y <= maxblock.Y; b_y++)
11381138
for (s16 b_z = minblock.Z; b_z <= maxblock.Z; b_z++) {
1139-
v3s16 blockpos(b_x, b_y, b_z);
1139+
const v3s16 blockpos(b_x, b_y, b_z);
11401140
MapBlock *block = map->getBlockNoCreateNoEx(blockpos);
11411141
if (!block || block->isDummy())
11421142
// Skip not existing blocks
@@ -1282,6 +1282,126 @@ void blit_back_with_light(ServerMap *map, MMVManip *vm,
12821282
modified_blocks);
12831283
}
12841284

1285+
/*!
1286+
* Resets the lighting of the given map block to
1287+
* complete darkness and full sunlight.
1288+
*
1289+
* \param light incoming sunlight, light[x][z] is true if there
1290+
* is sunlight above the map block at the given x-z coordinates.
1291+
* The array's indices are relative node coordinates in the block.
1292+
* After the procedure returns, this contains outgoing light at
1293+
* the bottom of the map block.
1294+
*/
1295+
void fill_with_sunlight(MapBlock *block, INodeDefManager *ndef,
1296+
bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE])
1297+
{
1298+
if (block->isDummy())
1299+
return;
1300+
// dummy boolean
1301+
bool is_valid;
1302+
// For each column of nodes:
1303+
for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
1304+
for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
1305+
// True if the current node has sunlight.
1306+
bool lig = light[z][x];
1307+
// For each node, downwards:
1308+
for (s16 y = MAP_BLOCKSIZE - 1; y >= 0; y--) {
1309+
MapNode n = block->getNodeNoCheck(x, y, z, &is_valid);
1310+
// Ignore IGNORE nodes, these are not generated yet.
1311+
if (n.getContent() == CONTENT_IGNORE)
1312+
continue;
1313+
const ContentFeatures &f = ndef->get(n.getContent());
1314+
if (lig && !f.sunlight_propagates) {
1315+
// Sunlight is stopped.
1316+
lig = false;
1317+
}
1318+
// Reset light
1319+
n.setLight(LIGHTBANK_DAY, lig ? 15 : 0, f);
1320+
n.setLight(LIGHTBANK_NIGHT, 0, f);
1321+
block->setNodeNoCheck(x, y, z, n);
1322+
}
1323+
// Output outgoing light.
1324+
light[z][x] = lig;
1325+
}
1326+
}
1327+
1328+
void repair_block_light(ServerMap *map, MapBlock *block,
1329+
std::map<v3s16, MapBlock*> *modified_blocks)
1330+
{
1331+
if (!block || block->isDummy())
1332+
return;
1333+
INodeDefManager *ndef = map->getNodeDefManager();
1334+
// First queue is for day light, second is for night light.
1335+
UnlightQueue unlight[] = { UnlightQueue(256), UnlightQueue(256) };
1336+
ReLightQueue relight[] = { ReLightQueue(256), ReLightQueue(256) };
1337+
// Will hold sunlight data.
1338+
bool lights[MAP_BLOCKSIZE][MAP_BLOCKSIZE];
1339+
SunlightPropagationData data;
1340+
// Dummy boolean.
1341+
bool is_valid;
1342+
1343+
// --- STEP 1: reset everything to sunlight
1344+
1345+
mapblock_v3 blockpos = block->getPos();
1346+
(*modified_blocks)[blockpos] = block;
1347+
// For each map block:
1348+
// Extract sunlight above.
1349+
is_sunlight_above_block(map, blockpos, ndef, lights);
1350+
// Reset the voxel manipulator.
1351+
fill_with_sunlight(block, ndef, lights);
1352+
// Copy sunlight data
1353+
data.target_block = v3s16(blockpos.X, blockpos.Y - 1, blockpos.Z);
1354+
for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
1355+
for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
1356+
data.data.push_back(
1357+
SunlightPropagationUnit(v2s16(x, z), lights[z][x]));
1358+
}
1359+
// Propagate sunlight and shadow below the voxel manipulator.
1360+
while (!data.data.empty()) {
1361+
if (propagate_block_sunlight(map, ndef, &data, &unlight[0],
1362+
&relight[0]))
1363+
(*modified_blocks)[data.target_block] =
1364+
map->getBlockNoCreateNoEx(data.target_block);
1365+
// Step downwards.
1366+
data.target_block.Y--;
1367+
}
1368+
1369+
// --- STEP 2: Get nodes from borders to unlight
1370+
1371+
// For each border of the block:
1372+
for (direction d = 0; d < 6; d++) {
1373+
VoxelArea a = block_pad[d];
1374+
// For each node of the border:
1375+
for (s32 x = a.MinEdge.X; x <= a.MaxEdge.X; x++)
1376+
for (s32 z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++)
1377+
for (s32 y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
1378+
v3s16 relpos(x, y, z);
1379+
// Get node
1380+
MapNode node = block->getNodeNoCheck(x, y, z, &is_valid);
1381+
const ContentFeatures &f = ndef->get(node);
1382+
// For each light bank
1383+
for (size_t b = 0; b < 2; b++) {
1384+
LightBank bank = banks[b];
1385+
u8 light = f.param_type == CPT_LIGHT ?
1386+
node.getLightNoChecks(bank, &f):
1387+
f.light_source;
1388+
// If the new node is dimmer than sunlight, unlight.
1389+
// (if it has maximal light, it is pointless to remove
1390+
// surrounding light, as it can only become brighter)
1391+
if (LIGHT_SUN > light) {
1392+
unlight[b].push(
1393+
LIGHT_SUN, relpos, blockpos, block, 6);
1394+
}
1395+
} // end of banks
1396+
} // end of nodes
1397+
} // end of borders
1398+
1399+
// STEP 3: Remove and spread light
1400+
1401+
finish_bulk_light_update(map, blockpos, blockpos, unlight, relight,
1402+
modified_blocks);
1403+
}
1404+
12851405
VoxelLineIterator::VoxelLineIterator(
12861406
const v3f &start_position,
12871407
const v3f &line_vector) :

‎src/voxelalgorithms.h

+9
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ void update_block_border_lighting(Map *map, MapBlock *block,
9797
void blit_back_with_light(ServerMap *map, MMVManip *vm,
9898
std::map<v3s16, MapBlock*> *modified_blocks);
9999

100+
/*!
101+
* Corrects the light in a map block.
102+
* For server use only.
103+
*
104+
* \param block the block to update
105+
*/
106+
void repair_block_light(ServerMap *map, MapBlock *block,
107+
std::map<v3s16, MapBlock*> *modified_blocks);
108+
100109
/*!
101110
* This class iterates trough voxels that intersect with
102111
* a line. The collision detection does not see nodeboxes,

0 commit comments

Comments
 (0)
Please sign in to comment.