[Mod] Delete unknown blocks and objects [1] [clean]

User avatar
JPRuehmann
Member
 
Posts: 334
Joined: Fri Mar 21, 2014 21:40

by JPRuehmann » Fri Apr 04, 2014 18:05

link is broken
 

User avatar
hoodedice
Member
 
Posts: 1372
Joined: Sat Jul 06, 2013 06:33

by hoodedice » Fri Apr 04, 2014 18:15

JPRuehmann wrote:link is broken


1. Make a folder called 'clean'. (Without quotes)
2. Right click, scroll to 'New'. Click 'Text files' in the context menu.
3. Rename text file to 'init.lua' (Without quotes). Open it.
4. Go to first link in thread, copy entire stuff in the code box.
5. Paste stuff into new text file you made.
6. Just to be sure, click 'File', 'Save As...' and type "init.lua" (WITH Quotes) and save.
7. ???
8. Only if everyone used GitHub...
7:42 PM - Bauglio: I think if you go to staples you could steal firmware from a fax machine that would run better than win10 does on any platform
7:42 PM - Bauglio: so fudge the stable build
7:43 PM - Bauglio: get the staple build
 

User avatar
JPRuehmann
Member
 
Posts: 334
Joined: Fri Mar 21, 2014 21:40

by JPRuehmann » Sat Apr 05, 2014 20:14

It works.
Thanks,
JPR
 

User avatar
Inocudom
Member
 
Posts: 2889
Joined: Sat Sep 29, 2012 01:14
IRC: Inocudom
In-game: Inocudom

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by Inocudom » Wed Jul 02, 2014 02:37

This mod dates from almost two years ago. Surely, there must be more efficient ways of removing unknown nodes now. First, there would have to be a way to detect them...
 

prestidigitator
Member
 
Posts: 632
Joined: Thu Feb 21, 2013 23:54

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by prestidigitator » Sat Jul 05, 2014 08:56

I THINK this would do the trick without manual configuration, but it's obviously a lot less simple. See what you think. The code is WTFPL.

There's a caveat: at the moment it will keep a table entry in memory for every 80x80x80 block nearby positions connected players visit. That's a bit of a "memory leak", but if it's not acceptable that could be fixed relatively easily by keeping some kind of freshness value and ousting old entries once the size gets too big.

Your 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 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);
 

prestidigitator
Member
 
Posts: 632
Joined: Thu Feb 21, 2013 23:54

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by prestidigitator » Sat Jul 05, 2014 09:36

Okay. Realized I could do a little better. This version uses node metadata and a maximum TODO queue size to avoid the "memory leak". Again, WTFPL.

Your 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 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);


(EDIT, 2014-07-18: Fixed small bug on list add/remove.)
 

Marshall_maz
Member
 
Posts: 240
Joined: Mon Jul 14, 2014 17:13
In-game: Mazal

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by Marshall_maz » Sat Feb 14, 2015 16:51

This works brilliantly , thanx
 

User avatar
Linuxdirk
Member
 
Posts: 497
Joined: Wed Sep 17, 2014 11:21
GitHub: dsohler
In-game: Linuxdirk

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by Linuxdirk » Sat Mar 14, 2015 15:07

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?
 

User avatar
Don
Member
 
Posts: 1641
Joined: Sat May 17, 2014 18:40
GitHub: DonBatman
IRC: Batman
In-game: Batman

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by Don » Sat Mar 14, 2015 17:53

This should be a part of minetest. Should be added to server commands.
Many of my mods are now a part of Minetest-mods. A place where you know they are maintained!

A list of my mods can be found here
 

prestidigitator
Member
 
Posts: 632
Joined: Thu Feb 21, 2013 23:54

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by prestidigitator » Mon Apr 06, 2015 11:12

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?

It would probably require operating directly on the database file for the world. I haven't taken a look at the schema, but I seriously doubt that would be fun. I suspect it might even involve mirroring how Minetest parses BLOBs of node data....
 

User avatar
12Me21
Member
 
Posts: 826
Joined: Tue Mar 05, 2013 00:36

Re:

by 12Me21 » Mon Apr 06, 2015 13:30

PilzAdam wrote:
rubenwardy wrote:How to use?

local old_nodes = {xpanes:pane} does not work

Your 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"}

No, you need to do:
local old_nodes = {"{"{"{"{"xpanes:pane"}"}"}"}"}
 

bbaez
Member
 
Posts: 50
Joined: Wed Jul 09, 2014 15:24

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by bbaez » Sun Nov 15, 2015 18:33

Just letting future viewers know to try this when /clearobjects just keeps on segmentation fault (incrementing but who knows how many times until all is finally cleared).

I created a directory called clean with depends.txt containing default and init.lua containg the code posted by prestidigitator.

Thanks for the code!
 

OneIce
New member
 
Posts: 1
Joined: Thu Aug 18, 2016 06:39
IRC: OneIce
In-game: OneIce

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by OneIce » Sat Aug 20, 2016 23:58

+1
as a Newbie to modding, this was very Useful.
 

User avatar
poikilos
Member
 
Posts: 32
Joined: Thu Feb 18, 2016 13:45
GitHub: poikilos
In-game: poikilos

Re:

by poikilos » Fri Jan 27, 2017 16:50

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 like
Your 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.txt
Your 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.


Calling it new_name, old_name confused me for a while--I looked it up and https://dev.minetest.net/minetest.register_alias explains that it is actually (name, convert_to)
such that if mod providing "name" doesn't exist (is "old") then mod "convert_to" will be used instead. So in some usages such as that, case name, convert_to param names are more clear.
 

User avatar
QwertyDragon
Member
 
Posts: 11
Joined: Sat Dec 24, 2016 15:37
GitHub: QwertyDragon
IRC: QwertyDragon
In-game: QwertyDragon LittleBigBunny

Re: [Mod] Delete unknown blocks and objects [1] [clean]

by QwertyDragon » Wed Mar 08, 2017 23:09

Don wrote:This should be a part of minetest. Should be added to server commands.

+1

Maybe:
https://github.com/indriApollo/remove_unknown
 

Previous

Return to Mod Releases

Who is online

Users browsing this forum: No registered users and 27 guests

cron