JPRuehmann wrote:link is broken
local CLEANUP_PERIOD__S = 10.0;
local ENTITY_CLEANUP_RADIUS = 80.0;
local NODES_PER_BLOCK = 80;
local function hashPos(pos)
return 32*pos.z + 16*pos.y + pos.x;
end
local function posEqual(ap, bp)
return (ap.x == bp.x) and (ap.y == bp.y) and (ap.z == bp.z);
end
local function nodePosToBlockPos(pos)
return {
x = math.floor(pos.x / NODES_PER_BLOCK),
y = math.floor(pos.y / NODES_PER_BLOCK),
z = math.floor(pos.z / NODES_PER_BLOCK)
};
end
local function blockPosToNodePos(pos)
return {
x = NODES_PER_BLOCK * pos.x,
y = NODES_PER_BLOCK * pos.y,
z = NODES_PER_BLOCK * pos.z
};
end
local function cleanupEntitiesNear(pos)
local objs = minetest.get_objects_inside_radius(pos, ENTITY_CLEANUP_RADIUS);
for _, obj in ipairs(objs) do
local pname = obj.get_player_name and obj:get_player_name();
local entity = obj.get_luaentity and obj:get_luaentity();
if entity then
if entity.name == "__builtin:item" then
local istr = entity.itemstring;
local itemName = istr and ItemStack(istr):get_name();
local def = itemName and itemName ~= "" and
(minetest.registered_entities[itemName] or
minetest.registered_items[itemName] or
minetest.registered_nodes[itemName] or
minetest.registered_craftitems[itemName] or
minetest.registered_tools[itemName]);
if not def then
obj:remove();
end
end
elseif not pname or pname == "" then
obj:remove();
end
end
end
local addCache;
do
local cache = {};
addCache = function(pos)
local h = hashPos(pos);
local parr = cache[h];
if not parr then
cache[h] = { pos };
return true;
else
for _, p in ipairs(parr) do
if posEqual(pos, p) then
return false;
end
end
table.insert(parr, pos);
return true;
end
end
end
local addToDo;
local removeToDo;
do
local head = nil;
local tail = nil;
addToDo = function(pos)
local n = { pos = pos };
if tail then
tail.next = n;
tail = n;
else
head = n;
tail = n;
end
end
removeToDo = function()
if not head then return nil; end
local n = head;
head = n.next;
return n.pos;
end
end
local function markClean(minp, maxp)
local bpmin = nodePosToBlockPos(minp);
local bpmax = nodePosToBlockPos(maxp);
for x = bpmin.x, bpmax.x do
for y = bpmin.y, bpmax.y do
for z = bpmin.z, bpmax.z do
addCache({ x = x, y = y, z = z });
end
end
end
end
local function registerCleanupBlocks(pos)
local bp = nodePosToBlockPos(pos);
for x = bp.x-1, bp.x+1 do
for y = bp.y-1, bp.y+1 do
for z = bp.z-1, bp.z+1 do
local bp = { x = x, y = y, z = z };
if addCache(bp) then
addToDo(bp);
end
end
end
end
end
local function cleanupBlock()
local bp = removeToDo();
if not bp then return; end
local pmin = blockPosToNodePos(bp);
local pmax = blockPosToNodePos({ x = bp.x+1, y = bp.y+1, z = bp.z+1 });
pmax.x = pmax.x-1; -- make inclusive
pmax.y = pmax.y-1;
pmax.z = pmax.z-1;
local vm = VoxelManip();
pmin, pmax = vm:read_from_map(pmin, pmax);
local va = VoxelArea:new({ MinEdge = pmin, MaxEdge = pmax });
local data = vm:get_data();
local airCid = minetest.get_content_id("air");
local replaced = 0;
for i, cid in ipairs(data) do
local nodeName = minetest.get_name_from_content_id(cid);
if not minetest.registered_nodes[nodeName] then
data[i] = airCid;
replaced = replaced + 1;
end
end
if replaced > 0 then
vm:set_data(data);
vm:write_to_map();
vm:update_map();
vm:update_liquids();
end
end
local function cleanup()
for _, player in ipairs(minetest.get_connected_players()) do
local pos = player:getpos();
cleanupEntitiesNear(pos);
registerCleanupBlocks(pos);
end
cleanupBlock();
end
do
local elapsedTime_s = 0;
minetest.register_globalstep(
function(dt_s)
elapsedTime_s = elapsedTime_s + dt_s;
if elapsedTime_s >= CLEANUP_PERIOD__S then
elapsedTime_s = 0;
cleanup();
end
end);
end
minetest.register_on_generated(
function(minp, maxp, blockSeed)
markClean(minp, maxp);
end);
local MOD_NAME = minetest.get_current_modname();
local CLEANUP_PERIOD__S = 10.0;
local ENTITY_CLEANUP_RADIUS = 80.0;
local NODES_PER_BLOCK = 80;
local FRESHNESS_META_KEY = MOD_NAME..":freshness";
local MAX_TODO_SIZE = 100;
local BATCH_SIZE = 3;
local startTime = minetest.get_gametime();
local function nodePosToBlockPos(pos)
return {
x = math.floor(pos.x / NODES_PER_BLOCK),
y = math.floor(pos.y / NODES_PER_BLOCK),
z = math.floor(pos.z / NODES_PER_BLOCK)
};
end
local function blockPosToNodePos(pos)
return {
x = NODES_PER_BLOCK * pos.x,
y = NODES_PER_BLOCK * pos.y,
z = NODES_PER_BLOCK * pos.z
};
end
local function cleanupEntitiesNear(pos)
local objs = minetest.get_objects_inside_radius(pos, ENTITY_CLEANUP_RADIUS);
for _, obj in ipairs(objs) do
local pname = obj.get_player_name and obj:get_player_name();
local entity = obj.get_luaentity and obj:get_luaentity();
if entity then
if entity.name == "__builtin:item" then
local istr = entity.itemstring;
local itemName = istr and ItemStack(istr):get_name();
local def = itemName and itemName ~= "" and
(minetest.registered_entities[itemName] or
minetest.registered_items[itemName] or
minetest.registered_nodes[itemName] or
minetest.registered_craftitems[itemName] or
minetest.registered_tools[itemName]);
if not def then
obj:remove();
end
end
elseif not pname or pname == "" then
obj:remove();
end
end
end
local function isBlockFresh(blockPos)
local pos = blockPosToNodePos(blockPos);
return minetest.get_meta(pos):get_int(FRESHNESS_META_KEY) == startTime;
end
local function setBlockFresh(blockPos)
local pos = blockPosToNodePos(blockPos);
minetest.get_meta(pos):set_int(FRESHNESS_META_KEY, startTime);
end
local addToDo;
local removeToDo;
do
local size = 0;
local head = nil;
local tail = nil;
addToDo = function(pos)
if size >= MAX_TODO_SIZE then return false; end
local n = { pos = pos };
if head then
tail.next = n;
tail = n;
else
head = n;
tail = n;
end
size = size + 1;
return true;
end
removeToDo = function()
if not head then return nil; end
local n = head;
head = n.next;
if not head then tail = nil; end
size = size - 1;
return n.pos;
end
end
local function markNodesClean(minp, maxp)
local bpmin = nodePosToBlockPos(minp);
local bpmax = nodePosToBlockPos(maxp);
for x = bpmin.x, bpmax.x do
for y = bpmin.y, bpmax.y do
for z = bpmin.z, bpmax.z do
setBlockFresh({ x = x, y = y, z = z });
end
end
end
end
local function registerCleanupBlocks(pos)
local bp = nodePosToBlockPos(pos);
for x = bp.x-1, bp.x+1 do
for y = bp.y-1, bp.y+1 do
for z = bp.z-1, bp.z+1 do
local bp = { x = x, y = y, z = z };
if not isBlockFresh(bp) then
local willDo = addToDo(bp);
if willDo then setBlockFresh(bp); end
end
end
end
end
end
local function cleanupBlock()
local bp = removeToDo();
if not bp then return false; end
local pmin = blockPosToNodePos(bp);
local pmax = blockPosToNodePos({ x = bp.x+1, y = bp.y+1, z = bp.z+1 });
pmax.x = pmax.x-1; -- make inclusive
pmax.y = pmax.y-1;
pmax.z = pmax.z-1;
local vm = VoxelManip();
pmin, pmax = vm:read_from_map(pmin, pmax);
local va = VoxelArea:new({ MinEdge = pmin, MaxEdge = pmax });
local data = vm:get_data();
local airCid = minetest.get_content_id("air");
local replaced = 0;
for i, cid in ipairs(data) do
local nodeName = minetest.get_name_from_content_id(cid);
if not minetest.registered_nodes[nodeName] then
data[i] = airCid;
replaced = replaced + 1;
end
end
if replaced > 0 then
vm:set_data(data);
vm:write_to_map();
vm:update_map();
vm:update_liquids();
end
return true;
end
local function cleanup()
for _, player in ipairs(minetest.get_connected_players()) do
local pos = player:getpos();
cleanupEntitiesNear(pos);
registerCleanupBlocks(pos);
end
for i = 1, BATCH_SIZE do
if not cleanupBlock() then break; end
end
end
do
local elapsedTime_s = 0;
minetest.register_globalstep(
function(dt_s)
elapsedTime_s = elapsedTime_s + dt_s;
if elapsedTime_s >= CLEANUP_PERIOD__S then
elapsedTime_s = 0;
cleanup();
end
end);
end
minetest.register_on_generated(
function(minp, maxp, blockSeed)
markNodesClean(minp, maxp);
end);
prestidigitator wrote:This version uses node metadata and a maximum TODO queue size to avoid the "memory leak".
Linuxdirk wrote:prestidigitator wrote:This version uses node metadata and a maximum TODO queue size to avoid the "memory leak".
Do you know a way to remove all unknown entities/nodes (even if currently not loaded) from a world?
PilzAdam wrote:rubenwardy wrote:How to use?
local old_nodes = {xpanes:pane} does not workYour phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
local old_nodes = {"xpanes:pane"}
PilzAdam wrote:mauvebic wrote:Feature request: renaming/migration
Say when you change the name of your mod, or the node, that you could do something likeYour phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
nodeswitch('teacup:teacup','tea:cup')
example use: i have a map that uses staircase, which ive updated and renamed since then to nbu, along with some of the nodenames. I cant switch the old mod for the new mod without ruining my map and i dont want to remove the UB's, just switch 'em :-)
From lua-api.txtYour phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
minetest.register_alias(new_name, old_name)
After that you can use both in code and game, new_name and old_name.
Don wrote:This should be a part of minetest. Should be added to server commands.
Users browsing this forum: No registered users and 27 guests