summaryrefslogtreecommitdiff
path: root/nodedb.lua
blob: de582f020e3ce896ff606c617b13f5b614ef053f (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
160
161
162
163
164
165
166
--nodedb.lua
--database of all nodes that have 'save_in_at_nodedb' field set to true in node definition

ndb_nodes_notrack = 0

--serialization format:
--(2byte z) (2byte y) (2byte x) (2byte contentid)
--contentid := (14bit nodeid, 2bit param2)

local function int_to_bytes(i)
	local x=i+32768--clip to positive integers
	local cH = math.floor(x /           256) % 256;
	local cL = math.floor(x                ) % 256;
	return(string.char(cH, cL));
end
local function bytes_to_int(bytes)
	local t={string.byte(bytes,1,-1)}
	local n = 
		t[1] *           256 +
		t[2]
    return n-32768
end
local function l2b(x)
	return x%4
end
local function u14b(x)
	return math.floor(x/4)
end
local ndb={}

--local variables for performance
local ndb_nodeids={}
local ndb_nodes={}

local function ndbget(x,y,z)
	local ny=ndb_nodes[y]
	if ny then
		local nx=ny[x]
		if nx then
			return nx[z]
		end
	end
	return nil
end
local function ndbset(x,y,z,v)
	if not ndb_nodes[y] then
		ndb_nodes[y]={}
	end
	if not ndb_nodes[y][x] then
		ndb_nodes[y][x]={}
	end
	ndb_nodes[y][x][z]=v
end


local path="advtrains_ndb2"
--load
--nodeids get loaded by advtrains init.lua and passed here
function ndb.load_data(data)
	ndb_nodeids = data and data.nodeids or {}
	local file, err = io.open(datapath..path, "rb")
	if not file then
		print("Couldn't load the node database: ", err or "Unknown Error")
	else
		local cnt=0
		local hst_z=file:read(2)
		local hst_y=file:read(2)
		local hst_x=file:read(2)
		local cid=file:read(2)
		while hst_z and hst_y and hst_x and cid and #hst_z==2 and #hst_y==2 and #hst_x==2 and #cid==2 do
			ndbset(bytes_to_int(hst_x), bytes_to_int(hst_y), bytes_to_int(hst_z), bytes_to_int(cid))
			cnt=cnt+1
			hst_z=file:read(2)
			hst_y=file:read(2)
			hst_x=file:read(2)
			cid=file:read(2)
		end
		print("nodedb: read", cnt, "nodes.")
		ndb_nodes_total = cnt
		file:close()
	end
end

--function to get node. track database is not helpful here.
function ndb.get_node_or_nil(pos)
	-- FIX for bug found on linuxworks server:
	-- a loaded node might get read before the LBM has updated its state, resulting in wrongly set signals and switches
	-- -> Using the saved node prioritarily.
	local node = ndb.get_node_raw(pos)
	if node then
		return node
	else
		-- no minetest here
		return nil
	end
end
function ndb.get_node(pos)
	local n=ndb.get_node_or_nil(pos)
	if not n then
		return {name="ignore", param2=0}
	end
	return n
end
function ndb.get_node_raw(pos)
	local cid=ndbget(pos.x, pos.y, pos.z)
	if cid then
		local nodeid = ndb_nodeids[u14b(cid)]
		if nodeid then
			return {name=nodeid, param2 = l2b(cid)}
		end
	end
	return nil
end

function ndb.clear(pos)
	ndbset(pos.x, pos.y, pos.z, nil)
end


--get_node with pseudoload. now we only need track data, so we can use the trackdb as second fallback
--nothing new will be saved inside the trackdb.
--returns:
--true, conn1, conn2, rely1, rely2, railheight   in case everything's right.
--false  if it's not a rail or the train does not drive on this rail, but it is loaded or
--nil    if the node is neither loaded nor in trackdb
--the distraction between false and nil will be needed only in special cases.(train initpos)
function advtrains.get_rail_info_at(pos)
	local rdp=advtrains.round_vector_floor_y(pos)
	
	local node=ndb.get_node_or_nil(rdp)
	if not node then return end
	
	local nodename=node.name
	
	local conns, railheight, tracktype=advtrains.get_track_connections(node.name, node.param2)
	
	if not conns then
		return false
	end
	
	return true, conns, railheight
end


-- mapper-specific

function ndb.mapper_find_starting_point()
	for y, ty in pairs(ndb_nodes) do
		for x, tx in pairs(ty) do
			for z, v in pairs(tx) do
				local pos = {x=x, y=y, z=z}
				local node_ok, conns, _ = advtrains.get_rail_info_at(pos)
				if node_ok then
					return pos, conns
				else
					-- this is a signal or something similar, ignore.
					tx[z]=nil
					ndb_nodes_notrack = ndb_nodes_notrack + 1
				end
			end
		end
	end
end


advtrains.ndb = ndb