mirror of
				https://github.com/minetest-mods/digilines.git
				synced 2025-11-04 08:05:28 +01:00 
			
		
		
		
	Use VoxelManipulators to force-load nodes.
If a node needed during wire traversal is not currently loaded, it is loaded from disk using a VoxelManipulator.
This commit is contained in:
		
				
					committed by
					
						
						Auke Kok
					
				
			
			
				
	
			
			
			
						parent
						
							514fb2e289
						
					
				
				
					commit
					25ea72270d
				
			@@ -14,7 +14,7 @@ function digiline:importrules(spec, node)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function digiline:getAnyInputRules(pos)
 | 
			
		||||
	local node = minetest.get_node(pos)
 | 
			
		||||
	local node = digiline:get_node_force(pos)
 | 
			
		||||
	local spec = digiline:getspec(node)
 | 
			
		||||
	if not spec then return end
 | 
			
		||||
 | 
			
		||||
@@ -27,7 +27,7 @@ function digiline:getAnyInputRules(pos)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function digiline:getAnyOutputRules(pos)
 | 
			
		||||
	local node = minetest.get_node(pos)
 | 
			
		||||
	local node = digiline:get_node_force(pos)
 | 
			
		||||
	local spec = digiline:getspec(node)
 | 
			
		||||
	if not spec then return end
 | 
			
		||||
 | 
			
		||||
@@ -86,11 +86,12 @@ local function queue_dequeue(queue)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function digiline:transmit(pos, channel, msg, checked)
 | 
			
		||||
	digiline:vm_begin()
 | 
			
		||||
	local queue = queue_new()
 | 
			
		||||
	queue_enqueue(queue, pos)
 | 
			
		||||
	while not queue_empty(queue) do
 | 
			
		||||
		local curPos = queue_dequeue(queue)
 | 
			
		||||
		local node = minetest.get_node(curPos)
 | 
			
		||||
		local node = digiline:get_node_force(curPos)
 | 
			
		||||
		local spec = digiline:getspec(node)
 | 
			
		||||
		if spec then
 | 
			
		||||
			-- Effector actions --> Receive
 | 
			
		||||
@@ -114,4 +115,5 @@ function digiline:transmit(pos, channel, msg, checked)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	digiline:vm_end()
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								util.lua
									
									
									
									
									
								
							
							
						
						
									
										89
									
								
								util.lua
									
									
									
									
									
								
							@@ -65,3 +65,92 @@ function digiline:tablecopy(table) -- deep table copy
 | 
			
		||||
 | 
			
		||||
	return newtable
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- VoxelManipulator-based node access functions:
 | 
			
		||||
 | 
			
		||||
-- Maps from a hashed mapblock position (as returned by hash_blockpos) to a
 | 
			
		||||
-- table.
 | 
			
		||||
--
 | 
			
		||||
-- Contents of the table are:
 | 
			
		||||
-- “va” → the VoxelArea
 | 
			
		||||
-- “data” → the data array
 | 
			
		||||
-- “param1” → the param1 array
 | 
			
		||||
-- “param2” → the param2 array
 | 
			
		||||
--
 | 
			
		||||
-- Nil if no bulk-VM operation is in progress.
 | 
			
		||||
local vm_cache = nil
 | 
			
		||||
 | 
			
		||||
-- Starts a bulk-VoxelManipulator operation.
 | 
			
		||||
--
 | 
			
		||||
-- During a bulk-VoxelManipulator operation, calls to get_node_force operate
 | 
			
		||||
-- directly on VM-loaded arrays, which should be faster for reading many nodes
 | 
			
		||||
-- in rapid succession. However, the cache must be flushed with vm_end once the
 | 
			
		||||
-- scan is finished, to avoid using stale data in future.
 | 
			
		||||
function digiline:vm_begin()
 | 
			
		||||
	vm_cache = {}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Ends a bulk-VoxelManipulator operation, freeing the cached data.
 | 
			
		||||
function digiline:vm_end()
 | 
			
		||||
	vm_cache = nil
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- The dimension of a mapblock in nodes.
 | 
			
		||||
local MAPBLOCKSIZE = 16
 | 
			
		||||
 | 
			
		||||
-- Converts a node position into a hash of a mapblock position.
 | 
			
		||||
local function vm_hash_blockpos(pos)
 | 
			
		||||
	return minetest.hash_node_position({
 | 
			
		||||
		x = math.floor(pos.x / MAPBLOCKSIZE),
 | 
			
		||||
		y = math.floor(pos.y / MAPBLOCKSIZE),
 | 
			
		||||
		z = math.floor(pos.z / MAPBLOCKSIZE)
 | 
			
		||||
	})
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Gets the cache entry covering a position, populating it if necessary.
 | 
			
		||||
local function vm_get_or_create_entry(pos)
 | 
			
		||||
	local hash = vm_hash_blockpos(pos)
 | 
			
		||||
	local tbl = vm_cache[hash]
 | 
			
		||||
	if not tbl then
 | 
			
		||||
		local vm = minetest.get_voxel_manip(pos, pos)
 | 
			
		||||
		local min_pos, max_pos = vm:get_emerged_area()
 | 
			
		||||
		local va = VoxelArea:new{MinEdge = min_pos, MaxEdge = max_pos}
 | 
			
		||||
		tbl = {va = va, data = vm:get_data(), param1 = vm:get_light_data(), param2 = vm:get_param2_data()}
 | 
			
		||||
		vm_cache[hash] = tbl
 | 
			
		||||
	end
 | 
			
		||||
	return tbl
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Gets the node at a position during a bulk-VoxelManipulator operation.
 | 
			
		||||
local function vm_get_node(pos)
 | 
			
		||||
	local tbl = vm_get_or_create_entry(pos)
 | 
			
		||||
	local index = tbl.va:indexp(pos)
 | 
			
		||||
	local node_value = tbl.data[index]
 | 
			
		||||
	local node_param1 = tbl.param1[index]
 | 
			
		||||
	local node_param2 = tbl.param2[index]
 | 
			
		||||
	return {name = minetest.get_name_from_content_id(node_value), param1 = node_param1, param2 = node_param2}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Gets the node at a given position, regardless of whether it is loaded or
 | 
			
		||||
-- not.
 | 
			
		||||
--
 | 
			
		||||
-- Outside a bulk-VoxelManipulator operation, if the mapblock is not loaded, it
 | 
			
		||||
-- is pulled into the server’s main map data cache and then accessed from
 | 
			
		||||
-- there.
 | 
			
		||||
--
 | 
			
		||||
-- Inside a bulk-VoxelManipulator operation, the operation’s VM cache is used.
 | 
			
		||||
function digiline:get_node_force(pos)
 | 
			
		||||
	if vm_cache then
 | 
			
		||||
		return vm_get_node(pos)
 | 
			
		||||
	end
 | 
			
		||||
	local node = minetest.get_node(pos)
 | 
			
		||||
	if node.name == "ignore" then
 | 
			
		||||
		-- Node is not currently loaded; use a VoxelManipulator to prime
 | 
			
		||||
		-- the mapblock cache and try again.
 | 
			
		||||
		minetest.get_voxel_manip(pos, pos)
 | 
			
		||||
		node = minetest.get_node(pos)
 | 
			
		||||
	end
 | 
			
		||||
	return node
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user