summaryrefslogtreecommitdiff
path: root/init.lua
blob: 6e67515b7b431f503ed7e831ac988cb06613381b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
local _pts = minetest.pos_to_string
function minetest.pos_to_string(pos)
	if not pos then
		return "(-,-,-)"
	end
	return _pts(pos)
end

-- Makes sure that force load areas are handled correctly
function ForceloadManager(filetoopen, hide_file_errors)
	local blocks = {}
	if filetoopen ~= nil then
		local file = io.open(filetoopen, "r")
		if file then
			local table = minetest.deserialize(file:read("*all"))
			file:close()
			if type(table) == "table" then
				blocks = table
			end
		elseif not hide_file_errors then
			minetest.log("error", "File "..filetoopen.." does not exist!")
		end
	end
	for i = 1, #blocks do
		if not minetest.forceload_block(blocks[i]) then			
			minetest.log("error", "Failed to load block " .. minetest.pos_to_string(blocks[i]))
		end
	end
	return {
		_blocks = blocks,
		load = function(self, pos)
			if minetest.forceload_block(pos) then
				table.insert(self._blocks, vector.new(pos))
				return true
			end
			minetest.log("error", "Failed to load block " .. minetest.pos_to_string(pos))
			return false
		end,
		unload = function(self, pos)
			for i = 1, #self._blocks do
				if vector.equals(pos, self._blocks[i]) then					
					minetest.forceload_block(pos)
					table.remove(self._blocks, i)
					return true
				end
			end
			return false
		end,
		iter = function(self, func)
			for i = 1, #self._blocks do
				if func(i, self._blocks[i]) == true then
					table.remove(self._blocks, i)
					i = i - 1
				end
			end
		end,
		save = function(self, filename)
			local file = io.open(filename, "w")
			if file then
				file:write(minetest.serialize(self._blocks))
				file:close()
			end
		end,
		verify = function(self)
			return self:verify_each(function(pos, block)				
				local name = "ignore"
				if block ~= nil then
					name = block.name
				end

				if name == "ignore" then	
					if not pos.last or elapsed_time > pos.last + 15 then
						pos.last = elapsed_time
						if not minetest.forceload_block(pos) then							
							minetest.log("error", "Failed to force load " .. minetest.pos_to_string(pos))
							pos.remove = true
						end
					end
					return false
				elseif name == "forceload:anchor" then
					pos.last = elapsed_time
					return true
				else	
					minetest.log("error", minetest.pos_to_string(pos) .. " shouldn't be loaded")
					pos.remove = true
					return false		
				end
			end)
		end,
		verify_each = function(self, func)
			local not_loaded = {}			
			for i = 1, #self._blocks do
				local res = minetest.get_node(self._blocks[i])
				if not func(self._blocks[i], res) then
					--[[table.insert(not_loaded, {
						pos = self._blocks[i],
						i = i,
						b = res })]]--
				end
			end
			return not_loaded
		end,
		clean = function(self)
			local i = 1
			while i <= #self._blocks do
				if self._blocks[i].remove then
					table.remove(self._blocks, i)
				else
					i = i + 1
				end
			end
		end
	}
end

local flm = ForceloadManager(minetest.get_worldpath().."/flm.json", true)

minetest.register_privilege("forceload", "Allows players to use forceload block anchors")

minetest.register_node("forceload:anchor",{
	description = "Block Anchor",
	walkable = false,
	tiles = {"forceload_anchor.png"},
	groups = {cracky = 3, oddly_breakable_by_hand = 2},
	after_destruct = function(pos)
		flm:unload(pos)
		flm:save(minetest.get_worldpath().."/flm.json")
	end,
	after_place_node = function(pos, placer)
		if not minetest.check_player_privs(placer:get_player_name(),
				{forceload = true}) then
			minetest.chat_send_player(placer:get_player_name(), "The forceload privilege is required to do that.")
		elseif flm:load(pos) then			
			flm:save(minetest.get_worldpath().."/flm.json")
			return
		end		
		minetest.set_node(pos, {name="air"})
		return true
	end
})

minetest.register_chatcommand("a", {func = function(name)
	flm:verify()
	flm:clean()
end})

local elapsed_time = 0
local count = 0
minetest.register_globalstep(function(dtime)
	count = count + dtime
	elapsed_time = elapsed_time + dtime
	if count > 5 then
		count = 0
		--print("Verifying...")
		flm:verify()
		flm:clean()
	end
end)