aboutsummaryrefslogtreecommitdiff
path: root/advtrains_train_track/models/advtrains_track_cr.b3d
blob: b0f5e4b247497b66dd8eefbb2942b39ae40cd108 (plain)
ofshex dumpascii
0000 42 42 33 44 4f 1f 00 00 01 00 00 00 54 45 58 53 25 00 00 00 72 61 69 6c 2e 70 6e 67 00 01 00 00 BB3DO.......TEXS%...rail.png....
0020 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 80 3f 00 00 80 3f 00 00 00 00 42 52 55 53 2e 00 00 ................?...?....BRUS...
0040 00 01 00 00 00 42 72 75 73 68 2e 30 30 31 00 00 00 80 3f 00 00 80 3f 00 00 80 3f 00 00 80 3f 00 .....Brush.001....?...?...?...?.
0060 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 4e 4f 44 45 e0 1e 00 00 72 61 69 6c 5f 34 35 5f 39 ...............NODE....rail_45_9
0080 30 69 00 00 00 e0 c0 00 00 80 be 00 00 80 40 ce cc cc 3e cd cc cc 3e 02 00 00 3f 5e 1c 7c 3f 00 0i............@...>...>...?^.|?.
00a0 00 00 00 d4 d0 31 3e 00 00 00 00 4d 45 53 48 a4 1e 00 00 ff ff ff ff 56 52 54 53 0c 1a 00 00 01 .....1>....MESH........VRTS.....
00c0 00 00 00 01 00 00 00 02 00 00 00 69 90 a7 3f 00 00 c0 be e3 1e 03 40 cd a3 66 3f fc c1 fd bd aa ...........i..?.......@..f?.....
00e0 e9 d4 be 0d 41 34 3f f6 b3 30 3f e2 29 da 3f 00 00 c0 be 20 bd c7 bf 80 df 3f 3f 20 11 10 be 4b ....A4?..0?.).?..........??....K
0100 97 25 bf bc fb 2e 3e f4 b3 30 3f c3 fe 91 3f 00 00 c0 be 9d b9 b2 bf bd 79 5e bf 85 b1 42 be d4 .%....>..0?...?.........y^...B..
0120 d1 e9 be c0 fb 2e 3e 1c c0 07 3f 99 eb 43 3f 00 00 c0 be 87 46 ec 3f 89 79 44 bf cb 51 65 be 34 ......>...?..C?.....F.?.yD..Qe.4
0140 c3 19 bf 0f 41 34 3f 20 c0 07 3f 8b ec 7d 3f cc cc 8c be 34 18 f7 3f 5b 95 2d bf fd b9 fe 3e 15 ....A4?...?..}?....4..?[.-....>.
0160 7f 0a bf 0e 41 34 3f bc be ea 3e b7 10 b0 3f cc cc 8c be 13 7b bb bf 2b 5b 15 bf 97 71 4b 3e 93 ....A4?...>...?.....{..+[...qK>.
0180 97 49 bf c8 fb 2e 3e b0 be ea 3e b8 10 b0 3f c0 cc cc bc 12 7b bb bf 19 71 0c bf a7 81 53 be 9f .I....>...>...?.....{...q....S..
01a0 65 4f bf ce fb 2e 3e 26 9e c8 3e 8b ec 7d 3f c0 cc cc bc 34 18 f7 3f 42 13 21 bf eb 49 75 be 7b eO....>&..>..}?....4..?B.!..Iu.{
01c0 47 3d 3f 0f 41 34 3f 36 9e c8 3e e8 17 bc 3f cc cc 8c be a9 fb be bf 03 89 81 3e 9f b1 cf 3e c2 G=?.A4?6..>...?...........>...>.
01e0 d7 60 bf ca fb 2e 3e a0 21 c7 3d e2 29 da 3f 00 00 c0 be 20 bd c7 bf 80 df 3f 3f 20 11 10 be 4b .`....>.!.=.).?..........??....K
0200 97 25 bf de fb 2e 3e 00 6e d0 3c 69 90 a7 3f 00 00 c0 be e3 1e 03 40 cd a3 66 3f fc c1 fd bd aa .%....>.n.<i..?.......@..f?.....
0220 e9 d4 be 16 41 34 3f c0 6e d0 3c 13 90 8a 3f cc cc 8c be 0a 6c fb 3f a4 19 52 3f 04 2f 02 3f 0b ....A4?.n.<...?.....l.?..R?./.?.
0240 51 85 be 12 41 34 3f e0 21 c7 3d e2 29 da 3f 00 00 c0 be 20 bd c7 bf 80 df 3f 3f 20 11 10 be 4b Q...A4?.!.=.).?..........??....K
0260 97 25 bf f8 e6 19 3d 2c 9f 4a 3e e8 17 bc 3f cc cc 8c be a9 fb be bf 03 89 81 3e 9f b1 cf 3e c2 .%....=,.J>...?...........>...>.
0280 d7 60 bf c4 8d 83 3d 28 70 87 3e b7 10 b0 3f cc cc 8c be 13 7b bb bf 2b 5b 15 bf 97 71 4b 3e 93 .`....=(p.>...?.....{..+[...qK>.
02a0 97 49 bf b8 8d 83 3d c6 16 95 3e c3 fe 91 3f 00 00 c0 be 9d b9 b2 bf bd 79 5e bf 85 b1 42 be d4 .I....=...>...?.........y^...B..
02c0 d1 e9 be 10 e6 19 3d 4c 37 b7 3e c3 fe 91 3f 00 00 c0 be 9d b9 b2 bf bd 79 5e bf 85 b1 42 be d4 ......=L7.>...?.........y^...B..
02e0 d1 e9 be c0 fb 2e 3e 1c c0 07 3f b7 10 b0 3f cc cc 8c be 13 7b bb bf 2b 5b 15 bf 97 71 4b 3e 93 ......>...?...?.....{..+[...qK>.
0300 97 49 bf c8 fb 2e 3e b0 be ea 3e 8b ec 7d 3f cc cc 8c be 34 18 f7 3f 5b 95 2d bf fd b9 fe 3e 15 .I....>...>..}?....4..?[.-....>.
0320 7f 0a bf 0e 41 34 3f bc be ea 3e 99 eb 43 3f 00 00 c0 be 87 46 ec 3f 89 79 44 bf cb 51 65 be 34 ....A4?...>..C?.....F.?.yD..Qe.4
0340 c3 19 bf 0f 41 34 3f 20 c0 07 3f 8b ec 7d 3f c0 cc cc bc 34 18 f7 3f 42 13 21 bf eb 49 75 be 7b ....A4?...?..}?....4..?B.!..Iu.{
0360 47 3d 3f 06 7e 3e 3f f4 16 95 3e 13 90 8a 3f c0 cc cc bc 0a 6c fb 3f 34 01 9a 3d 78 f5 bb be db G=?.~>?...>...?.....l.?4..=x....
0380 57 6d 3f 06 7e 3e 3f 56 70 87 3e 13 90 8a 3f cc cc 8c be 0a 6c fb 3f a4 19 52 3f 04 2f 02 3f 0b Wm?.~>?Vp.>...?.....l.?..R?./.?.
03a0 51 85 be 4a 8e 4f 3f 5c 70 87 3e 8b ec 7d 3f cc cc 8c be 34 18 f7 3f 5b 95 2d bf fd b9 fe 3e 15 Q..J.O?\p.>..}?....4..?[.-....>.
03c0 7f 0a bf 4a 8e 4f 3f f8 16 95 3e 13 90 8a 3f cc cc 8c be 0a 6c fb 3f a4 19 52 3f 04 2f 02 3f 0b ...J.O?...>...?.....l.?..R?./.?.
03e0 51 85 be 12 41 34 3f e0 21 c7 3d 13 90 8a 3f c0 cc cc bc 0a 6c fb 3f 34 01 9a 3d 78 f5 bb be db Q...A4?.!.=...?.....l.?4..=x....
0400 57 6d 3f 11 41 34 3f 00 d2 27 3e 6c 75 bb 3f c0 cc cc bc 59 cc be bf 39 91 1c 3e a6 f5 d2 be cc Wm?.A4?..'>lu.?....Y...9..>.....
0420 f1 65 bf c8 fb 2e 3e e4 d1 27 3e e8 17 bc 3f cc cc 8c be a9 fb be bf 03 89 81 3e 9f b1 cf 3e c2 .e....>..'>...?...........>...>.
0440 d7 60 bf ca fb 2e 3e a0 21 c7 3d b7 10 b0 3f cc cc 8c be 13 7b bb bf 2b 5b 15 bf 97 71 4b 3e 93 .`....>.!.=...?.....{..+[...qK>.
0460 97 49 bf b8 8d 83 3d c6 16 95 3e e8 17 bc 3f cc cc 8c be a9 fb be bf 03 89 81 3e 9f b1 cf 3e c2 .I....=...>...?...........>...>.
0480 d7 60 bf c4 8d 83 3d 28 70 87 3e 6c 75 bb 3f c0 cc cc bc 59 cc be bf 39 91 1c 3e a6 f5 d2 be cc .`....=(p.>lu.?....Y...9..>.....
04a0 f1 65 bf f8 07 06 3e 36 70 87 3e b8 10 b0 3f c0 cc cc bc 12 7b bb bf 19 71 0c bf a7 81 53 be 9f .e....>6p.>...?.....{...q....S..
04c0 65 4f bf f0 07 06 3e d0 16 95 3e 8b ec 7d 3f c0 cc cc bc 34 18 f7 3f 42 13 21 bf eb 49 75 be 7b eO....>...>..}?....4..?B.!..Iu.{
04e0 47 3d 3f 0f 41 34 3f 36 9e c8 3e b8 10 b0 3f c0 cc cc bc 12 7b bb bf 19 71 0c bf a7 81 53 be 9f G=?.A4?6..>...?.....{...q....S..
0500 65 4f bf ce fb 2e 3e 26 9e c8 3e bc 07 a1 3f 00 00 00 00 57 1a b7 bf 58 2f 2c bf 0b 85 05 bf 0d eO....>&..>...?....W...X/,......
0520 5f 06 bf ce fb 2e 3e 60 37 b7 3e 12 ec 60 3f 00 00 c0 32 5e af f1 3f 7e 39 3f bf 08 eb 03 bf ae _.....>`7.>..`?...2^..?~9?......
0540 11 d7 3e 10 41 34 3f 74 37 b7 3e 6c 75 bb 3f c0 cc cc bc 59 cc be bf 39 91 1c 3e a6 f5 d2 be cc ..>.A4?t7.>lu.?....Y...9..>.....
0560 f1 65 bf c8 fb 2e 3e e4 d1 27 3e 13 90 8a 3f c0 cc cc bc 0a 6c fb 3f 34 01 9a 3d 78 f5 bb be db .e....>..'>...?.....l.?4..=x....
0580 57 6d 3f 11 41 34 3f 00 d2 27 3e 50 10 99 3f 00 00 c0 32 70 6a 00 40 e3 65 f1 3e 02 0d 01 bf 72 Wm?.A4?..'>P..?...2pj.@.e.>....r
05a0 3b 39 3f 11 41 34 3f 8c 9f 4a 3e e3 20 cb 3f 00 00 00 00 64 5c c3 bf 24 03 12 3f 02 e1 00 bf 4c ;9?.A4?..J>...?....d\..$..?....L
05c0 23 26 bf c8 fb 2e 3e 6c 9f 4a 3e 12 ec 60 3f 00 00 c0 32 5e af f1 3f 7e 39 3f bf 08 eb 03 bf ae #&....>l.J>..`?...2^..?~9?......
05e0 11 d7 3e 10 41 34 3f 74 37 b7 3e bc 07 a1 3f 00 00 00 00 57 1a b7 bf 58 2f 2c bf 0b 85 05 bf 0d ..>.A4?t7.>...?....W...X/,......
0600 5f 06 bf ce fb 2e 3e 60 37 b7 3e bc 07 a1 3f ff ff ff 3d 57 1a b7 bf 39 61 1c bf 34 e5 19 3f 08 _.....>`7.>...?...=W...9a..4..?.
0620 e3 03 bf be fb 2e 3e 18 27 a6 3e 1e ec 60 3f 02 00 00 3e 57 af f1 3f 60 05 30 bf 2f 59 17 3f b0 ......>.'.>..`?...>W..?`.0./Y.?.
0640 cd d7 3e 0e 41 34 3f 36 27 a6 3e e3 20 cb 3f 00 00 00 00 64 5c c3 bf 24 03 12 3f 02 e1 00 bf 4c ..>.A4?6'.>...?....d\..$..?....L
0660 23 26 bf c8 fb 2e 3e 6c 9f 4a 3e 50 10 99 3f 00 00 c0 32 70 6a 00 40 e3 65 f1 3e 02 0d 01 bf 72 #&....>l.J>P..?...2pj.@.e.>....r
0680 3b 39 3f 11 41 34 3f 8c 9f 4a 3e 4d 10 99 3f 02 00 00 3e 74 6a 00 40 bb 55 dd 3e 22 c1 10 3f 68 ;9?.A4?..J>M..?...>tj.@.U.>"..?h
06a0 cf 33 3f 13 41 34 3f 1c c0 6c 3e e5 20 cb 3f 00 00 00 3e 64 5c c3 bf 11 83 08 3f 1e 35 0f 3f 45 .3?.A4?..l>...?...>d\.....?.5.?E
06c0 71 22 bf da fb 2e 3e e8 bf 6c 3e bc 07 a1 3f ff ff ff 3d 57 1a b7 bf 39 61 1c bf 34 e5 19 3f 08 q"....>..l>...?...=W...9a..4..?.
06e0 e3 03 bf be fb 2e 3e 18 27 a6 3e e5 20 cb 3f 00 00 00 3e 64 5c c3 bf 11 83 08 3f 1e 35 0f 3f 45 ......>.'.>...?...>d\.....?.5.?E
0700 71 22 bf da fb 2e 3e e8 bf 6c 3e 4d 10 99 3f 02 00 00 3e 74 6a 00 40 bb 55 dd 3e 22 c1 10 3f 68 q"....>..l>M..?...>tj.@.U.>"..?h
0720 cf 33 3f 13 41 34 3f 1c c0 6c 3e 1e ec 60 3f 02 00 00 3e 57 af f1 3f 60 05 30 bf 2f 59 17 3f b0 .3?.A4?..l>..`?...>W..?`.0./Y.?.
0740 cd d7 3e 0e 41 34 3f 36 27 a6 3e 13 90 8a 3f c0 cc cc bc 0a 6c fb 3f 34 01 9a 3d 78 f5 bb be db ..>.A4?6'.>...?.....l.?4..=x....
0760 57 6d 3f 06 7e 3e 3f 56 70 87 3e 8b ec 7d 3f c0 cc cc bc 34 18 f7 3f 42 13 21 bf eb 49 75 be 7b Wm?.~>?Vp.>..}?....4..?B.!..Iu.{
0780 47 3d 3f 06 7e 3e 3f f4 16 95 3e 50 10 99 3f 00 00 c0 32 70 6a 00 40 e3 65 f1 3e 02 0d 01 bf 72 G=?.~>?...>P..?...2pj.@.e.>....r
07a0 3b 39 3f 35 c9 3c 3f 20 c0 6c 3e 8b ec 7d 3f c0 cc cc bc 34 18 f7 3f 42 13 21 bf eb 49 75 be 7b ;9?5.<?..l>..}?....4..?B.!..Iu.{
07c0 47 3d 3f 06 7e 3e 3f f4 16 95 3e 12 ec 60 3f 00 00 c0 32 5e af f1 3f 7e 39 3f bf 08 eb 03 bf ae G=?.~>?...>..`?...2^..?~9?......
07e0 11 d7 3e 31 c9 3c 3f 38 27 a6 3e 1e ec 60 3f 02 00 00 3e 57 af f1 3f 60 05 30 bf 2f 59 17 3f b0 ..>1.<?8'.>..`?...>W..?`.0./Y.?.
0800 cd d7 3e 0e 41 34 3f 36 27 a6 3e 1e ec 60 3f 02 00 00 3e 57 af f1 3f 60 05 30 bf 2f 59 17 3f b0 ..>.A4?6'.>..`?...>W..?`.0./Y.?.
0820 cd d7 3e 0e 41 34 3f 36 27 a6 3e 4d 10 99 3f 02 00 00 3e 74 6a 00 40 bb 55 dd 3e 22 c1 10 3f 68 ..>.A4?6'.>M..?...>tj.@.U.>"..?h
0840 cf 33 3f 13 41 34 3f 1c c0 6c 3e 50 10 99 3f 00 00 c0 32 70 6a 00 40 e3 65 f1 3e 02 0d 01 bf 72 .3?.A4?..l>P..?...2pj.@.e.>....r
0860 3b 39 3f 35 c9 3c 3f 20 c0 6c 3e 8b ec 7d 3f c0 cc cc bc 34 18 f7 3f 42 13 21 bf eb 49 75 be 7b ;9?5.<?..l>..}?....4..?B.!..Iu.{
0880 47 3d 3f 06 7e 3e 3f f4 16 95 3e 1e ec 60 3f 02 00 00 3e 57 af f1 3f 60 05 30 bf 2f 59 17 3f b0 G=?.~>?...>..`?...>W..?`.0./Y.?.
08a0 cd d7 3e 0e 41 34 3f 36 27 a6 3e 50 10 99 3f 00 00 c0 32 70 6a 00 40 e3 65 f1 3e 02 0d 01 bf 72 ..>.A4?6'.>P..?...2pj.@.e.>....r
08c0 3b 39 3f 35 c9 3c 3f 20 c0 6c 3e 6c 75 bb 3f c0 cc cc bc 59 cc be bf 39 91 1c 3e a6 f5 d2 be cc ;9?5.<?..l>lu.?....Y...9..>.....
08e0 f1 65 bf f8 07 06 3e 36 70 87 3e e3 20 cb 3f 00 00 00 00 64 5c c3 bf 24 03 12 3f 02 e1 00 bf 4c .e....>6p.>...?....d\..$..?....L
0900 23 26 bf 52 db 0c 3e e0 bf 6c 3e b8 10 b0 3f c0 cc cc bc 12 7b bb bf 19 71 0c bf a7 81 53 be 9f #&.R..>..l>...?.....{...q....S..
0920 65 4f bf f0 07 06 3e d0 16 95 3e e3 20 cb 3f 00 00 00 00 64 5c c3 bf 24 03 12 3f 02 e1 00 bf 4c eO....>...>...?....d\..$..?....L
0940 23 26 bf 52 db 0c 3e e0 bf 6c 3e e5 20 cb 3f 00 00 00 3e 64 5c c3 bf 11 83 08 3f 1e 35 0f 3f 45 #&.R..>..l>...?...>d\.....?.5.?E
0960 71 22 bf da fb 2e 3e e8 bf 6c 3e bc 07 a1 3f ff ff ff 3d 57 1a b7 bf 39 61 1c bf 34 e5 19 3f 08 q"....>..l>...?...=W...9a..4..?.
0980 e3 03 bf be fb 2e 3e 18 27 a6 3e bc 07 a1 3f ff ff ff 3d 57 1a b7 bf 39 61 1c bf 34 e5 19 3f 08 ......>.'.>...?...=W...9a..4..?.
09a0 e3 03 bf be fb 2e 3e 18 27 a6 3e bc 07 a1 3f 00 00 00 00 57 1a b7 bf 58 2f 2c bf 0b 85 05 bf 0d ......>.'.>...?....W...X/,......
09c0 5f 06 bf 34 db 0c 3e 18 27 a6 3e b8 10 b0 3f c0 cc cc bc 12 7b bb bf 19 71 0c bf a7 81 53 be 9f _..4..>.'.>...?.....{...q....S..
09e0 65 4f bf f0 07 06 3e d0 16 95 3e e3 20 cb 3f 00 00 00 00 64 5c c3 bf 24 03 12 3f 02 e1 00 bf 4c eO....>...>...?....d\..$..?....L
0a00 23 26 bf 52 db 0c 3e e0 bf 6c 3e bc 07 a1 3f ff ff ff 3d 57 1a b7 bf 39 61 1c bf 34 e5 19 3f 08 #&.R..>..l>...?...=W...9a..4..?.
0a20 e3 03 bf be fb 2e 3e 18 27 a6 3e b8 10 b0 3f c0 cc cc bc 12 7b bb bf 19 71 0c bf a7 81 53 be 9f ......>.'.>...?.....{...q....S..
0a40 65 4f bf f0 07 06 3e d0 16 95 3e 75 9b 10 c0 00 00 c0 be d6 ae 37 3f 4a cd 24 3f 57 a1 2b be 7e eO....>...>u.........7?J.$?W.+.~
0a60 21 3f 3f 18 41 34 3f 17 c0 07 3f 09 71 ff bf 00 00 c0 be 51 58 f7 be 87 bf 43 3f 03 a9 01 be 44 !??.A4?...?.q......QX....C?....D
0a80 c1 21 bf c8 fb 2e 3e 1b c0 07 3f 12 ce 23 c0 00 00 c0 be 3b 4a a3 be a6 05 53 bf 9d 99 4e be 0f .!....>...?..#.....;J....S...N..
0aa0 69 07 bf d0 fb 2e 3e f6 b3 30 3f d5 68 33 c0 00 00 c0 be 6b c0 03 3f e9 79 74 bf 71 59 38 be e3 i.....>..0?.h3.....k..?.yt.qY8..
0ac0 49 71 3e 1b 41 34 3f ee b3 30 3f 98 e8 24 c0 cc cc 8c be c5 63 19 3f 63 7f 31 bf 09 49 84 3e 58 Iq>.A4?..0?..$......c.?c.1..I.>X
0ae0 33 2c 3f 15 41 34 3f 50 21 c7 3d 18 c5 14 c0 cc cc 8c be 1e 50 c6 be 1b 6b 0d bf 62 01 31 3e a1 3,?.A4?P!.=.........P...k..b.1>.
0b00 bf 50 bf c0 fb 2e 3e 60 21 c7 3d 18 c5 14 c0 c0 cc cc bc 1e 50 c6 be 0c 07 06 bf 6e d9 36 be aa .P....>`!.=.........P......n.6..
0b20 41 55 bf c2 fb 2e 3e cc d1 27 3e 98 e8 24 c0 c0 cc cc bc c5 63 19 3f 4b 83 25 bf 16 25 8b be 6d AU....>..'>..$......c.?K.%..%..m
0b40 7b 36 3f 15 41 34 3f c0 d1 27 3e 75 9b 10 c0 00 00 c0 be d6 ae 37 3f 4a cd 24 3f 57 a1 2b be 7e {6?.A4?..'>u.........7?J.$?W.+.~
0b60 21 3f 3f 18 41 34 3f 17 c0 07 3f b1 1b 1f c0 cc cc 8c be 72 0b 22 3f 1c 41 0e 3e 43 85 a1 3e e1 !??.A4?...?........r."?.A.>C..>.
0b80 4d 70 3f 16 41 34 3f a2 be ea 3e 81 c1 0e c0 cc cc 8c be 86 52 d4 be 12 c5 88 3e c9 61 e4 3e b5 Mp?.A4?...>.........R.....>.a.>.
0ba0 ab 5a bf b8 fb 2e 3e a8 be ea 3e 09 71 ff bf 00 00 c0 be 51 58 f7 be 87 bf 43 3f 03 a9 01 be 44 .Z....>...>.q......QX....C?....D
0bc0 c1 21 bf c8 fb 2e 3e 1b c0 07 3f 09 71 ff bf 00 00 c0 be 51 58 f7 be 87 bf 43 3f 03 a9 01 be 44 .!....>...?.q......QX....C?....D
0be0 c1 21 bf 10 e6 19 3d 58 37 b7 3e 81 c1 0e c0 cc cc 8c be 86 52 d4 be 12 c5 88 3e c9 61 e4 3e b5 .!....=X7.>.........R.....>.a.>.
0c00 ab 5a bf 94 8d 83 3d cc 16 95 3e 18 c5 14 c0 cc cc 8c be 1e 50 c6 be 1b 6b 0d bf 62 01 31 3e a1 .Z....=...>.........P...k..b.1>.
0c20 bf 50 bf a0 8d 83 3d 2e 70 87 3e 12 ce 23 c0 00 00 c0 be 3b 4a a3 be a6 05 53 bf 9d 99 4e be 0f .P....=.p.>..#.....;J....S...N..
0c40 69 07 bf 60 e6 19 3d 40 9f 4a 3e 12 ce 23 c0 00 00 c0 be 3b 4a a3 be a6 05 53 bf 9d 99 4e be 0f i..`..=@.J>..#.....;J....S...N..
0c60 69 07 bf bc fb 2e 3e c0 6c d0 3c 18 c5 14 c0 cc cc 8c be 1e 50 c6 be 1b 6b 0d bf 62 01 31 3e a1 i.....>.l.<.........P...k..b.1>.
0c80 bf 50 bf c0 fb 2e 3e 60 21 c7 3d 98 e8 24 c0 cc cc 8c be c5 63 19 3f 63 7f 31 bf 09 49 84 3e 58 .P....>`!.=..$......c.?c.1..I.>X
0ca0 33 2c 3f 15 41 34 3f 50 21 c7 3d d5 68 33 c0 00 00 c0 be 6b c0 03 3f e9 79 74 bf 71 59 38 be e3 3,?.A4?P!.=.h3.....k..?.yt.qY8..
0cc0 49 71 3e 16 41 34 3f c0 6c d0 3c b1 1b 1f c0 cc cc 8c be 72 0b 22 3f 1c 41 0e 3e 43 85 a1 3e e1 Iq>.A4?.l.<........r."?.A.>C..>.
0ce0 4d 70 3f 50 8e 4f 3f c8 16 95 3e 75 9b 10 c0 00 00 c0 be d6 ae 37 3f 4a cd 24 3f 57 a1 2b be 7e Mp?P.O?...>u.........7?J.$?W.+.~
0d00 21 3f 3f 9e 61 56 3f 54 37 b7 3e d5 68 33 c0 00 00 c0 be 6b c0 03 3f e9 79 74 bf 71 59 38 be e3 !??.aV?T7.>.h3.....k..?.yt.qY8..
0d20 49 71 3e 9e 61 56 3f 40 9f 4a 3e 98 e8 24 c0 cc cc 8c be c5 63 19 3f 63 7f 31 bf 09 49 84 3e 58 Iq>.aV?@.J>..$......c.?c.1..I.>X
0d40 33 2c 3f 50 8e 4f 3f 28 70 87 3e 98 e8 24 c0 c0 cc cc bc c5 63 19 3f 4b 83 25 bf 16 25 8b be 6d 3,?P.O?(p.>..$......c.?K.%..%..m
0d60 7b 36 3f 0b 7e 3e 3f 26 70 87 3e b1 1b 1f c0 c0 cc cc bc 72 0b 22 3f f5 81 7a 3d 53 95 a9 be e2 {6?.~>?&p.>........r."?..z=S....
0d80 09 71 3f 0b 7e 3e 3f c6 16 95 3e b1 1b 1f c0 cc cc 8c be 72 0b 22 3f 1c 41 0e 3e 43 85 a1 3e e1 .q?.~>?...>........r."?.A.>C..>.
0da0 4d 70 3f 50 8e 4f 3f c8 16 95 3e 98 e8 24 c0 cc cc 8c be c5 63 19 3f 63 7f 31 bf 09 49 84 3e 58 Mp?P.O?...>..$......c.?c.1..I.>X
0dc0 33 2c 3f 50 8e 4f 3f 28 70 87 3e b1 1b 1f c0 cc cc 8c be 72 0b 22 3f 1c 41 0e 3e 43 85 a1 3e e1 3,?P.O?(p.>........r."?.A.>C..>.
0de0 4d 70 3f 16 41 34 3f a2 be ea 3e b1 1b 1f c0 c0 cc cc bc 72 0b 22 3f f5 81 7a 3d 53 95 a9 be e2 Mp?.A4?...>........r."?..z=S....
0e00 09 71 3f 15 41 34 3f 18 9e c8 3e 81 c1 0e c0 c0 cc cc bc 86 52 d4 be 46 c9 22 3e d8 c1 eb be bf .q?.A4?...>.........R..F.">.....
0e20 8f 5f bf b8 fb 2e 3e 1c 9e c8 3e 81 c1 0e c0 cc cc 8c be 86 52 d4 be 12 c5 88 3e c9 61 e4 3e b5 ._....>...>.........R.....>.a.>.
0e40 ab 5a bf b8 fb 2e 3e a8 be ea 3e 18 c5 14 c0 cc cc 8c be 1e 50 c6 be 1b 6b 0d bf 62 01 31 3e a1 .Z....>...>.........P...k..b.1>.
0e60 bf 50 bf a0 8d 83 3d 2e 70 87 3e 81 c1 0e c0 cc cc 8c be 86 52 d4 be 12 c5 88 3e c9 61 e4 3e b5 .P....=.p.>.........R.....>.a.>.
0e80 ab 5a bf 94 8d 83 3d cc 16 95 3e 81 c1 0e c0 c0 cc cc bc 86 52 d4 be 46 c9 22 3e d8 c1 eb be bf .Z....=...>.........R..F.">.....
0ea0 8f 5f bf de 07 06 3e d0 16 95 3e 18 c5 14 c0 c0 cc cc bc 1e 50 c6 be 0c 07 06 bf 6e d9 36 be aa ._....>...>.........P......n.6..
0ec0 41 55 bf e4 07 06 3e 32 70 87 3e 98 e8 24 c0 c0 cc cc bc c5 63 19 3f 4b 83 25 bf 16 25 8b be 6d AU....>2p.>..$......c.?K.%..%..m
0ee0 7b 36 3f 15 41 34 3f c0 d1 27 3e 18 c5 14 c0 c0 cc cc bc 1e 50 c6 be 0c 07 06 bf 6e d9 36 be aa {6?.A4?..'>.........P......n.6..
0f00 41 55 bf c2 fb 2e 3e cc d1 27 3e 96 49 1c c0 00 00 c0 32 31 cd b4 be 42 e7 20 bf 0e fb 06 bf 25 AU....>..'>.I.....21...B.......%
0f20 5d 12 bf c0 fb 2e 3e 58 9f 4a 3e b7 28 2c c0 00 00 c0 32 19 92 0e 3f 8f b7 47 bf 05 4b 02 bf 74 ].....>X.J>.(,....2...?..G..K..t
0f40 39 ba 3e 15 41 34 3f 44 9f 4a 3e 81 c1 0e c0 c0 cc cc bc 86 52 d4 be 46 c9 22 3e d8 c1 eb be bf 9.>.A4?D.J>.........R..F.">.....
0f60 8f 5f bf b8 fb 2e 3e 1c 9e c8 3e b1 1b 1f c0 c0 cc cc bc 72 0b 22 3f f5 81 7a 3d 53 95 a9 be e2 ._....>...>........r."?..z=S....
0f80 09 71 3f 15 41 34 3f 18 9e c8 3e 93 db 17 c0 00 00 c0 32 1e dd 2c 3f bc 1d de 3e 02 0b 01 bf 7e .q?.A4?...>.......2..,?...>....~
0fa0 2b 3f 3f 15 41 34 3f 4e 37 b7 3e 03 3d 07 c0 00 00 c0 32 73 d5 e5 be 35 7b 1a 3f 01 51 00 bf 3e +??.A4?N7.>.=.....2s...5{.?.Q..>
0fc0 c3 1e bf b6 fb 2e 3e 5a 37 b7 3e b7 28 2c c0 00 00 c0 32 19 92 0e 3f 8f b7 47 bf 05 4b 02 bf 74 ......>Z7.>.(,....2...?..G..K..t
0fe0 39 ba 3e 15 41 34 3f 44 9f 4a 3e 96 49 1c c0 00 00 c0 32 31 cd b4 be 42 e7 20 bf 0e fb 06 bf 25 9.>.A4?D.J>.I.....21...B.......%
1000 5d 12 bf c0 fb 2e 3e 58 9f 4a 3e 96 49 1c c0 02 00 00 3e 31 cd b4 be 21 69 10 bf 39 a3 1c 3f 1c ].....>X.J>.I.....>1...!i..9..?.
1020 ef 0d bf c0 fb 2e 3e e4 bf 6c 3e b7 28 2c c0 02 00 00 3e 19 92 0e 3f 72 2f 39 bf 2a 0f 15 3f 7c ......>..l>.(,....>...?r/9.*..?|
1040 ed bd 3e 16 41 34 3f c4 bf 6c 3e 03 3d 07 c0 00 00 c0 32 73 d5 e5 be 35 7b 1a 3f 01 51 00 bf 3e ..>.A4?..l>.=.....2s...5{.?.Q..>
1060 c3 1e bf b6 fb 2e 3e 5a 37 b7 3e 93 db 17 c0 00 00 c0 32 1e dd 2c 3f bc 1d de 3e 02 0b 01 bf 7e ......>Z7.>.......2..,?...>....~
1080 2b 3f 3f 15 41 34 3f 4e 37 b7 3e 93 db 17 c0 02 00 00 3e 1e dd 2c 3f 8e 15 c7 3e 24 21 12 3f 72 +??.A4?N7.>.......>..,?...>$!.?r
10a0 1f 39 3f 15 41 34 3f 08 27 a6 3e 03 3d 07 c0 02 00 00 3e 73 d5 e5 be 25 43 12 3f 1c 1d 0e 3f 35 .9?.A4?.'.>.=.....>s...%C.?...?5
10c0 bd 1a bf b6 fb 2e 3e 18 27 a6 3e 96 49 1c c0 02 00 00 3e 31 cd b4 be 21 69 10 bf 39 a3 1c 3f 1c ......>.'.>.I.....>1...!i..9..?.
10e0 ef 0d bf c0 fb 2e 3e e4 bf 6c 3e 03 3d 07 c0 02 00 00 3e 73 d5 e5 be 25 43 12 3f 1c 1d 0e 3f 35 ......>..l>.=.....>s...%C.?...?5
1100 bd 1a bf b6 fb 2e 3e 18 27 a6 3e 93 db 17 c0 02 00 00 3e 1e dd 2c 3f 8e 15 c7 3e 24 21 12 3f 72 ......>.'.>.......>..,?...>$!.?r
1120 1f 39 3f 15 41 34 3f 08 27 a6 3e b7 28 2c c0 02 00 00 3e 19 92 0e 3f 72 2f 39 bf 2a 0f 15 3f 7c .9?.A4?.'.>.(,....>...?r/9.*..?|
1140 ed bd 3e 16 41 34 3f c4 bf 6c 3e b1 1b 1f c0 c0 cc cc bc 72 0b 22 3f f5 81 7a 3d 53 95 a9 be e2 ..>.A4?..l>........r."?..z=S....
1160 09 71 3f 0b 7e 3e 3f c6 16 95 3e 98 e8 24 c0 c0 cc cc bc c5 63 19 3f 4b 83 25 bf 16 25 8b be 6d .q?.~>?...>..$......c.?K.%..%..m
1180 7b 36 3f 0b 7e 3e 3f 26 70 87 3e 93 db 17 c0 00 00 c0 32 1e dd 2c 3f bc 1d de 3e 02 0b 01 bf 7e {6?.~>?&p.>.......2..,?...>....~
11a0 2b 3f 3f 36 c9 3c 3f 08 27 a6 3e 98 e8 24 c0 c0 cc cc bc c5 63 19 3f 4b 83 25 bf 16 25 8b be 6d +??6.<?.'.>..$......c.?K.%..%..m
11c0 7b 36 3f 0b 7e 3e 3f 26 70 87 3e b7 28 2c c0 00 00 c0 32 19 92 0e 3f 8f b7 47 bf 05 4b 02 bf 74 {6?.~>?&p.>.(,....2...?..G..K..t
11e0 39 ba 3e 38 c9 3c 3f c4 bf 6c 3e b7 28 2c c0 02 00 00 3e 19 92 0e 3f 72 2f 39 bf 2a 0f 15 3f 7c 9.>8.<?..l>.(,....>...?r/9.*..?|
1200 ed bd 3e 16 41 34 3f c4 bf 6c 3e b7 28 2c c0 02 00 00 3e 19 92 0e 3f 72 2f 39 bf 2a 0f 15 3f 7c ..>.A4?..l>.(,....>...?r/9.*..?|
1220 ed bd 3e 16 41 34 3f c4 bf 6c 3e 93 db 17 c0 02 00 00 3e 1e dd 2c 3f 8e 15 c7 3e 24 21 12 3f 72 ..>.A4?..l>.......>..,?...>$!.?r
1240 1f 39 3f 15 41 34 3f 08 27 a6 3e 93 db 17 c0 00 00 c0 32 1e dd 2c 3f bc 1d de 3e 02 0b 01 bf 7e .9?.A4?.'.>.......2..,?...>....~
1260 2b 3f 3f 36 c9 3c 3f 08 27 a6 3e 98 e8 24 c0 c0 cc cc bc c5 63 19 3f 4b 83 25 bf 16 25 8b be 6d +??6.<?.'.>..$......c.?K.%..%..m
1280 7b 36 3f 0b 7e 3e 3f 26 70 87 3e b7 28 2c c0 02 00 00 3e 19 92 0e 3f 72 2f 39 bf 2a 0f 15 3f 7c {6?.~>?&p.>.(,....>...?r/9.*..?|
12a0 ed bd 3e 16 41 34 3f c4 bf 6c 3e 93 db 17 c0 00 00 c0 32 1e dd 2c 3f bc 1d de 3e 02 0b 01 bf 7e ..>.A4?..l>.......2..,?...>....~
12c0 2b 3f 3f 36 c9 3c 3f 08 27 a6 3e 81 c1 0e c0 c0 cc cc bc 86 52 d4 be 46 c9 22 3e d8 c1 eb be bf +??6.<?.'.>.........R..F.">.....
12e0 8f 5f bf de 07 06 3e d0 16 95 3e 03 3d 07 c0 00 00 c0 32 73 d5 e5 be 35 7b 1a 3f 01 51 00 bf 3e ._....>...>.=.....2s...5{.?.Q..>
1300 c3 1e bf 2a db 0c 3e 18 27 a6 3e 18 c5 14 c0 c0 cc cc bc 1e 50 c6 be 0c 07 06 bf 6e d9 36 be aa ...*..>.'.>.........P......n.6..
1320 41 55 bf e4 07 06 3e 32 70 87 3e 03 3d 07 c0 00 00 c0 32 73 d5 e5 be 35 7b 1a 3f 01 51 00 bf 3e AU....>2p.>.=.....2s...5{.?.Q..>
1340 c3 1e bf 2a db 0c 3e 18 27 a6 3e 03 3d 07 c0 02 00 00 3e 73 d5 e5 be 25 43 12 3f 1c 1d 0e 3f 35 ...*..>.'.>.=.....>s...%C.?...?5
1360 bd 1a bf b6 fb 2e 3e 18 27 a6 3e 96 49 1c c0 02 00 00 3e 31 cd b4 be 21 69 10 bf 39 a3 1c 3f 1c ......>.'.>.I.....>1...!i..9..?.
1380 ef 0d bf c0 fb 2e 3e e4 bf 6c 3e 96 49 1c c0 02 00 00 3e 31 cd b4 be 21 69 10 bf 39 a3 1c 3f 1c ......>..l>.I.....>1...!i..9..?.
13a0 ef 0d bf c0 fb 2e 3e e4 bf 6c 3e 96 49 1c c0 00 00 c0 32 31 cd b4 be 42 e7 20 bf 0e fb 06 bf 25 ......>..l>.I.....21...B.......%
13c0 5d 12 bf 38 db 0c 3e e0 bf 6c 3e 18 c5 14 c0 c0 cc cc bc 1e 50 c6 be 0c 07 06 bf 6e d9 36 be aa ]..8..>..l>.........P......n.6..
13e0 41 55 bf e4 07 06 3e 32 70 87 3e 03 3d 07 c0 00 00 c0 32 73 d5 e5 be 35 7b 1a 3f 01 51 00 bf 3e AU....>2p.>.=.....2s...5{.?.Q..>
1400 c3 1e bf 2a db 0c 3e 18 27 a6 3e 96 49 1c c0 02 00 00 3e 31 cd b4 be 21 69 10 bf 39 a3 1c 3f 1c ...*..>.'.>.I.....>1...!i..9..?.
1420 ef 0d bf c0 fb 2e 3e e4 bf 6c 3e 18 c5 14 c0 c0 cc cc bc 1e 50 c6 be 0c 07 06 bf 6e d9 36 be aa ......>..l>.........P......n.6..
1440 41 55 bf e4 07 06 3e 32 70 87 3e 69 90 a7 3f 00 00 c0 be e3 1e 03 40 cd a3 66 3f fc c1 fd bd aa AU....>2p.>i..?.......@..f?.....
1460 e9 d4 be f8 e6 19 3d 2c 9f 4a 3e 13 90 8a 3f cc cc 8c be 0a 6c fb 3f a4 19 52 3f 04 2f 02 3f 0b ......=,.J>...?.....l.?..R?./.?.
1480 51 85 be c4 8d 83 3d 28 70 87 3e 8b ec 7d 3f cc cc 8c be 34 18 f7 3f 5b 95 2d bf fd b9 fe 3e 15 Q.....=(p.>..}?....4..?[.-....>.
14a0 7f 0a bf b8 8d 83 3d c6 16 95 3e 99 eb 43 3f 00 00 c0 be 87 46 ec 3f 89 79 44 bf cb 51 65 be 34 ......=...>..C?.....F.?.yD..Qe.4
14c0 c3 19 bf 10 e6 19 3d 4c 37 b7 3e ec 6a 53 c0 00 00 20 bf c8 75 47 3d 21 93 10 bf 27 63 13 bf 2f ......=L7.>.jS......uG=!...'c../
14e0 5b 17 3f c9 b7 1d 3d f8 64 59 3f 46 20 25 40 00 00 20 bf 4c d8 34 be 23 bd 11 3f 2a 1f 15 bf 29 [.?...=.dY?F.%@....L.4.#..?*...)
1500 83 14 3f 7e 24 76 3f fa 64 59 3f 0d 07 27 40 00 00 20 bf 2c 31 32 bf 27 45 13 3f 24 19 12 bf 2c ..?~$v?.dY?..'@....,12.'E.?$...,
1520 01 16 bf 7e 24 76 3f d9 7d 46 3f b8 8f 53 c0 00 00 20 bf 14 96 7e be 33 51 19 bf 29 bb 14 bf 1a ...~$v?.}F?..S.......~.3Q..)....
1540 15 0d bf 8e b7 1d 3d d6 7d 46 3f e8 6a 53 c0 00 00 c0 be 48 75 47 3d 21 93 10 bf 27 63 13 3f 2f ......=.}F?.jS.....HuG=!...'c.?/
1560 5b 17 3f 05 b8 1d 3d 59 3d 63 3f b8 8f 53 c0 00 00 c0 be 34 96 7e be 33 51 19 bf 29 bb 14 3f 1a [.?...=Y=c?..S.....4.~.3Q..)..?.
1580 15 0d bf c9 b7 1d 3d 7a 24 76 3f 0d 07 27 40 00 00 c0 be 28 31 32 bf 27 45 13 3f 24 17 12 3f 2c ......=z$v?..'@....(12.'E.?$..?,
15a0 01 16 bf 7b 24 76 3f 84 24 76 3f 4e 20 25 40 00 00 c0 be 7c d8 34 be 23 bd 11 3f 2a 1f 15 3f 29 ...{$v?.$v?N.%@....|.4.#..?*..?)
15c0 83 14 3f 83 24 76 3f 62 3d 63 3f ec 6a 53 c0 00 00 20 bf c8 75 47 3d 21 93 10 bf 27 63 13 bf 2f ..?.$v?b=c?.jS......uG=!...'c../
15e0 5b 17 3f c9 b7 1d 3d f8 64 59 3f e8 6a 53 c0 00 00 c0 be 48 75 47 3d 21 93 10 bf 27 63 13 3f 2f [.?...=.dY?.jS.....HuG=!...'c.?/
1600 5b 17 3f 05 b8 1d 3d 59 3d 63 3f 4e 20 25 40 00 00 c0 be 7c d8 34 be 23 bd 11 3f 2a 1f 15 3f 29 [.?...=Y=c?N.%@....|.4.#..?*..?)
1620 83 14 3f 83 24 76 3f 62 3d 63 3f 46 20 25 40 00 00 20 bf 4c d8 34 be 23 bd 11 3f 2a 1f 15 bf 29 ..?.$v?b=c?F.%@....L.4.#..?*...)
1640 83 14 3f 7e 24 76 3f fa 64 59 3f 46 20 25 40 00 00 20 bf 4c d8 34 be 23 bd 11 3f 2a 1f 15 bf 29 ..?~$v?.dY?F.%@....L.4.#..?*...)
1660 83 14 3f e4 fc 7f 3f 66 3d 63 3f 4e 20 25 40 00 00 c0 be 7c d8 34 be 23 bd 11 3f 2a 1f 15 3f 29 ..?...?f=c?N.%@....|.4.#..?*..?)
1680 83 14 3f 83 24 76 3f 62 3d 63 3f 0d 07 27 40 00 00 c0 be 28 31 32 bf 27 45 13 3f 24 17 12 3f 2c ..?.$v?b=c?..'@....(12.'E.?$..?,
16a0 01 16 bf 7b 24 76 3f 84 24 76 3f 0d 07 27 40 00 00 20 bf 2c 31 32 bf 27 45 13 3f 24 19 12 bf 2c ...{$v?.$v?..'@....,12.'E.?$...,
16c0 01 16 bf dd fc 7f 3f 88 24 76 3f 0d 07 27 40 00 00 20 bf 2c 31 32 bf 27 45 13 3f 24 19 12 bf 2c ......?.$v?..'@....,12.'E.?$...,
16e0 01 16 bf 7b 24 76 3f e5 fc 7f 3f 0d 07 27 40 00 00 c0 be 28 31 32 bf 27 45 13 3f 24 17 12 3f 2c ...{$v?...?..'@....(12.'E.?$..?,
1700 01 16 bf 7b 24 76 3f 84 24 76 3f b8 8f 53 c0 00 00 c0 be 34 96 7e be 33 51 19 bf 29 bb 14 3f 1a ...{$v?.$v?..S.....4.~.3Q..)..?.
1720 15 0d bf c9 b7 1d 3d 7a 24 76 3f b8 8f 53 c0 00 00 20 bf 14 96 7e be 33 51 19 bf 29 bb 14 bf 1a ......=z$v?..S.......~.3Q..)....
1740 15 0d bf 8e b7 1d 3d e3 fc 7f 3f e8 6a 53 c0 00 00 c0 be 48 75 47 3d 21 93 10 bf 27 63 13 3f 2f ......=...?.jS.....HuG=!...'c.?/
1760 5b 17 3f 05 b8 1d 3d 59 3d 63 3f ec 6a 53 c0 00 00 20 bf c8 75 47 3d 21 93 10 bf 27 63 13 bf 2f [.?...=Y=c?.jS......uG=!...'c../
1780 5b 17 3f 0c b1 47 38 56 3d 63 3f b8 8f 53 c0 00 00 20 bf 14 96 7e be 33 51 19 bf 29 bb 14 bf 1a [.?..G8V=c?..S.......~.3Q..)....
17a0 15 0d bf c7 c3 46 38 77 24 76 3f b8 8f 53 c0 00 00 c0 be 34 96 7e be 33 51 19 bf 29 bb 14 3f 1a .....F8w$v?..S.....4.~.3Q..)..?.
17c0 15 0d bf c9 b7 1d 3d 7a 24 76 3f 88 3e 5a c0 00 00 20 bf cb 4a cc 3e 61 ab 30 bf 29 9b 14 bf ba ......=z$v?.>Z......J.>a.0.)....
17e0 3d dd 3e c9 b7 1d 3d f8 64 59 3f 99 33 0b 40 00 00 20 bf 9a ad ed 3f 66 ed b2 3e 2c 2f 16 bf 76 =.>...=.dY?.3.@.......?f..>,/..v
1800 01 3b 3f 7e 24 76 3f fa 64 59 3f 5b 23 1c 40 00 00 20 bf 96 6e a2 3f 76 fb 3a 3f 22 d5 10 bf 88 .;?~$v?.dY?[#.@.....n.?v.:?"....
1820 e5 c3 be 7e 24 76 3f d9 7d 46 3f df a6 57 c0 00 00 20 bf 89 5b 48 3e d5 69 ea be 28 fd 13 bf 5a ...~$v?.}F?..W......[H>.i..(...Z
1840 e7 2c bf 8e b7 1d 3d d6 7d 46 3f 84 3e 5a c0 00 00 c0 be bb 4a cc 3e 61 ab 30 bf 29 9b 14 3f ba .,....=.}F?.>Z......J.>a.0.)..?.
1860 3d dd 3e 05 b8 1d 3d 59 3d 63 3f df a6 57 c0 00 00 c0 be 69 5b 48 3e d5 69 ea be 28 fd 13 3f 5a =.>...=Y=c?..W.....i[H>.i..(..?Z
1880 e7 2c bf c9 b7 1d 3d 7a 24 76 3f 5b 23 1c 40 00 00 c0 be 98 6e a2 3f 76 fb 3a 3f 22 d5 10 3f 88 .,....=z$v?[#.@.....n.?v.:?"..?.
18a0 e5 c3 be 7b 24 76 3f 84 24 76 3f a1 33 0b 40 00 00 c0 be 94 ad ed 3f 66 f1 b2 3e 2c 2f 16 3f 76 ...{$v?.$v?.3.@.......?f..>,/.?v
18c0 01 3b 3f 83 24 76 3f 62 3d 63 3f 88 3e 5a c0 00 00 20 bf cb 4a cc 3e 61 ab 30 bf 29 9b 14 bf ba .;?.$v?b=c?.>Z......J.>a.0.)....
18e0 3d dd 3e c9 b7 1d 3d f8 64 59 3f 84 3e 5a c0 00 00 c0 be bb 4a cc 3e 61 ab 30 bf 29 9b 14 3f ba =.>...=.dY?.>Z......J.>a.0.)..?.
1900 3d dd 3e 05 b8 1d 3d 59 3d 63 3f a1 33 0b 40 00 00 c0 be 94 ad ed 3f 66 f1 b2 3e 2c 2f 16 3f 76 =.>...=Y=c?.3.@.......?f..>,/.?v
1920 01 3b 3f 83 24 76 3f 62 3d 63 3f 99 33 0b 40 00 00 20 bf 9a ad ed 3f 66 ed b2 3e 2c 2f 16 bf 76 .;?.$v?b=c?.3.@.......?f..>,/..v
1940 01 3b 3f 7e 24 76 3f fa 64 59 3f 99 33 0b 40 00 00 20 bf 9a ad ed 3f 66 ed b2 3e 2c 2f 16 bf 76 .;?~$v?.dY?.3.@.......?f..>,/..v
1960 01 3b 3f e4 fc 7f 3f 66 3d 63 3f a1 33 0b 40 00 00 c0 be 94 ad ed 3f 66 f1 b2 3e 2c 2f 16 3f 76 .;?...?f=c?.3.@.......?f..>,/.?v
1980 01 3b 3f 83 24 76 3f 62 3d 63 3f 5b 23 1c 40 00 00 c0 be 98 6e a2 3f 76 fb 3a 3f 22 d5 10 3f 88 .;?.$v?b=c?[#.@.....n.?v.:?"..?.
19a0 e5 c3 be 7b 24 76 3f 84 24 76 3f 5b 23 1c 40 00 00 20 bf 96 6e a2 3f 76 fb 3a 3f 22 d5 10 bf 88 ...{$v?.$v?[#.@.....n.?v.:?"....
19c0 e5 c3 be dd fc 7f 3f 88 24 76 3f 5b 23 1c 40 00 00 20 bf 96 6e a2 3f 76 fb 3a 3f 22 d5 10 bf 88 ......?.$v?[#.@.....n.?v.:?"....
19e0 e5 c3 be 7b 24 76 3f e5 fc 7f 3f 5b 23 1c 40 00 00 c0 be 98 6e a2 3f 76 fb 3a 3f 22 d5 10 3f 88 ...{$v?...?[#.@.....n.?v.:?"..?.
1a00 e5 c3 be 7b 24 76 3f 84 24 76 3f df a6 57 c0 00 00 c0 be 69 5b 48 3e d5 69 ea be 28 fd 13 3f 5a ...{$v?.$v?..W.....i[H>.i..(..?Z
1a20 e7 2c bf c9 b7 1d 3d 7a 24 76 3f df a6 57 c0 00 00 20 bf 89 5b 48 3e d5 69 ea be 28 fd 13 bf 5a .,....=z$v?..W......[H>.i..(...Z
1a40 e7 2c bf 8e b7 1d 3d e3 fc 7f 3f 84 3e 5a c0 00 00 c0 be bb 4a cc 3e 61 ab 30 bf 29 9b 14 3f ba .,....=...?.>Z......J.>a.0.)..?.
1a60 3d dd 3e 05 b8 1d 3d 59 3d 63 3f 88 3e 5a c0 00 00 20 bf cb 4a cc 3e 61 ab 30 bf 29 9b 14 bf ba =.>...=Y=c?.>Z......J.>a.0.)....
1a80 3d dd 3e 0c b1 47 38 56 3d 63 3f df a6 57 c0 00 00 20 bf 89 5b 48 3e d5 69 ea be 28 fd 13 bf 5a =.>..G8V=c?..W......[H>.i..(...Z
1aa0 e7 2c bf c7 c3 46 38 77 24 76 3f df a6 57 c0 00 00 c0 be 69 5b 48 3e d5 69 ea be 28 fd 13 3f 5a .,...F8w$v?..W.....i[H>.i..(..?Z
1ac0 e7 2c bf c9 b7 1d 3d 7a 24 76 3f 54 52 49 53 84 04 00 00 00 00 00 00 02 00 00 00 01 00 00 00 00 .,....=z$v?TRIS.................
1ae0 00 00 00 03 00 00 00 02 00 00 00 00 00 00 00 06 00 00 00 05 00 00 00 04 00 00 00 07 00 00 00 06 ................................
1b00 00 00 00 04 00 00 00 0a 00 00 00 09 00 00 00 08 00 00 00 0b 00 00 00 0a 00 00 00 08 00 00 00 0e ................................
1b20 00 00 00 0d 00 00 00 0c 00 00 00 0f 00 00 00 0e 00 00 00 0c 00 00 00 12 00 00 00 11 00 00 00 10 ................................
1b40 00 00 00 13 00 00 00 12 00 00 00 10 00 00 00 16 00 00 00 15 00 00 00 14 00 00 00 17 00 00 00 16 ................................
1b60 00 00 00 14 00 00 00 1a 00 00 00 19 00 00 00 18 00 00 00 1b 00 00 00 1a 00 00 00 18 00 00 00 1e ................................
1b80 00 00 00 1d 00 00 00 1c 00 00 00 1f 00 00 00 1e 00 00 00 1c 00 00 00 22 00 00 00 21 00 00 00 20 ......................."...!....
1ba0 00 00 00 23 00 00 00 22 00 00 00 20 00 00 00 26 00 00 00 25 00 00 00 24 00 00 00 27 00 00 00 26 ...#...".......&...%...$...'...&
1bc0 00 00 00 24 00 00 00 2a 00 00 00 29 00 00 00 28 00 00 00 2b 00 00 00 2a 00 00 00 28 00 00 00 2e ...$...*...)...(...+...*...(....
1be0 00 00 00 2d 00 00 00 2c 00 00 00 2f 00 00 00 2e 00 00 00 2c 00 00 00 32 00 00 00 31 00 00 00 30 ...-...,.../.......,...2...1...0
1c00 00 00 00 33 00 00 00 32 00 00 00 30 00 00 00 36 00 00 00 35 00 00 00 34 00 00 00 39 00 00 00 38 ...3...2...0...6...5...4...9...8
1c20 00 00 00 37 00 00 00 3c 00 00 00 3b 00 00 00 3a 00 00 00 3f 00 00 00 3e 00 00 00 3d 00 00 00 42 ...7...<...;...:...?...>...=...B
1c40 00 00 00 41 00 00 00 40 00 00 00 45 00 00 00 44 00 00 00 43 00 00 00 48 00 00 00 47 00 00 00 46 ...A...@...E...D...C...H...G...F
1c60 00 00 00 4b 00 00 00 4a 00 00 00 49 00 00 00 4e 00 00 00 4d 00 00 00 4c 00 00 00 4f 00 00 00 4e ...K...J...I...N...M...L...O...N
1c80 00 00 00 4c 00 00 00 52 00 00 00 51 00 00 00 50 00 00 00 53 00 00 00 52 00 00 00 50 00 00 00 56 ...L...R...Q...P...S...R...P...V
1ca0 00 00 00 55 00 00 00 54 00 00 00 57 00 00 00 56 00 00 00 54 00 00 00 5a 00 00 00 59 00 00 00 58 ...U...T...W...V...T...Z...Y...X
1cc0 00 00 00 5b 00 00 00 5a 00 00 00 58 00 00 00 5e 00 00 00 5d 00 00 00 5c 00 00 00 5f 00 00 00 5e ...[...Z...X...^...]...\..._...^
1ce0 00 00 00 5c 00 00 00 62 00 00 00 61 00 00 00 60 00 00 00 63 00 00 00 62 00 00 00 60 00 00 00 66 ...\...b...a...`...c...b...`...f
1d00 00 00 00 65 00 00 00 64 00 00 00 67 00 00 00 66 00 00 00 64 00 00 00 6a 00 00 00 69 00 00 00 68 ...e...d...g...f...d...j...i...h
1d20 00 00 00 6b 00 00 00 6a 00 00 00 68 00 00 00 6e 00 00 00 6d 00 00 00 6c 00 00 00 6f 00 00 00 6e ...k...j...h...n...m...l...o...n
1d40 00 00 00 6c 00 00 00 72 00 00 00 71 00 00 00 70 00 00 00 73 00 00 00 72 00 00 00 70 00 00 00 76 ...l...r...q...p...s...r...p...v
1d60 00 00 00 75 00 00 00 74 00 00 00 77 00 00 00 76 00 00 00 74 00 00 00 7a 00 00 00 79 00 00 00 78 ...u...t...w...v...t...z...y...x
1d80 00 00 00 7b 00 00 00 7a 00 00 00 78 00 00 00 7e 00 00 00 7d 00 00 00 7c 00 00 00 7f 00 00 00 7e ...{...z...x...~...}...|.......~
1da0 00 00 00 7c 00 00 00 82 00 00 00 81 00 00 00 80 00 00 00 83 00 00 00 82 00 00 00 80 00 00 00 86 ...|............................
1dc0 00 00 00 85 00 00 00 84 00 00 00 89 00 00 00 88 00 00 00 87 00 00 00 8c 00 00 00 8b 00 00 00 8a ................................
1de0 00 00 00 8f 00 00 00 8e 00 00 00 8d 00 00 00 92 00 00 00 91 00 00 00 90 00 00 00 95 00 00 00 94 ................................
1e00 00 00 00 93 00 00 00 98 00 00 00 97 00 00 00 96 00 00 00 9b 00 00 00 9a 00 00 00 99 00 00 00 9e ................................
1e20 00 00 00 9d 00 00 00 9c 00 00 00 9f 00 00 00 9e 00 00 00 9c 00 00 00 a2 00 00 00 a1 00 00 00 a0 ................................
1e40 00 00 00 a3 00 00 00 a2 00 00 00 a0 00 00 00 a6 00 00 00 a5 00 00 00 a4 00 00 00 a7 00 00 00 a6 ................................
1e60 00 00 00 a4 00 00 00 aa 00 00 00 a9 00 00 00 a8 00 00 00 ab 00 00 00 aa 00 00 00 a8 00 00 00 ae ................................
1e80 00 00 00 ad 00 00 00 ac 00 00 00 af 00 00 00 ae 00 00 00 ac 00 00 00 b2 00 00 00 b1 00 00 00 b0 ................................
1ea0 00 00 00 b3 00 00 00 b2 00 00 00 b0 00 00 00 b6 00 00 00 b5 00 00 00 b4 00 00 00 b7 00 00 00 b6 ................................
1ec0 00 00 00 b4 00 00 00 ba 00 00 00 b9 00 00 00 b8 00 00 00 bb 00 00 00 ba 00 00 00 b8 00 00 00 be ................................
1ee0 00 00 00 bd 00 00 00 bc 00 00 00 bf 00 00 00 be 00 00 00 bc 00 00 00 c2 00 00 00 c1 00 00 00 c0 ................................
1f00 00 00 00 c3 00 00 00 c2 00 00 00 c0 00 00 00 c6 00 00 00 c5 00 00 00 c4 00 00 00 c7 00 00 00 c6 ................................
1f20 00 00 00 c4 00 00 00 ca 00 00 00 c9 00 00 00 c8 00 00 00 cb 00 00 00 ca 00 00 00 c8 00 00 00 ce ................................
1f40 00 00 00 cd 00 00 00 cc 00 00 00 cf 00 00 00 ce 00 00 00 cc 00 00 00 .......................
1581' href='#n1581'>1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377
/*
Minetest
Copyright (C) 2010-2017 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "serverenvironment.h"
#include "content_sao.h"
#include "settings.h"
#include "log.h"
#include "mapblock.h"
#include "nodedef.h"
#include "nodemetadata.h"
#include "gamedef.h"
#include "map.h"
#include "porting.h"
#include "profiler.h"
#include "raycast.h"
#include "remoteplayer.h"
#include "scripting_server.h"
#include "server.h"
#include "util/serialize.h"
#include "util/basic_macros.h"
#include "util/pointedthing.h"
#include "threading/mutex_auto_lock.h"
#include "filesys.h"
#include "gameparams.h"
#include "database/database-dummy.h"
#include "database/database-files.h"
#include "database/database-sqlite3.h"
#if USE_POSTGRESQL
#include "database/database-postgresql.h"
#endif
#include <algorithm>

#define LBM_NAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_:"

// A number that is much smaller than the timeout for particle spawners should/could ever be
#define PARTICLE_SPAWNER_NO_EXPIRY -1024.f

/*
	ABMWithState
*/

ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
	abm(abm_)
{
	// Initialize timer to random value to spread processing
	float itv = abm->getTriggerInterval();
	itv = MYMAX(0.001, itv); // No less than 1ms
	int minval = MYMAX(-0.51*itv, -60); // Clamp to
	int maxval = MYMIN(0.51*itv, 60);   // +-60 seconds
	timer = myrand_range(minval, maxval);
}

/*
	LBMManager
*/

void LBMContentMapping::deleteContents()
{
	for (auto &it : lbm_list) {
		delete it;
	}
}

void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef)
{
	// Add the lbm_def to the LBMContentMapping.
	// Unknown names get added to the global NameIdMapping.
	const NodeDefManager *nodedef = gamedef->ndef();

	lbm_list.push_back(lbm_def);

	for (const std::string &nodeTrigger: lbm_def->trigger_contents) {
		std::vector<content_t> c_ids;
		bool found = nodedef->getIds(nodeTrigger, c_ids);
		if (!found) {
			content_t c_id = gamedef->allocateUnknownNodeId(nodeTrigger);
			if (c_id == CONTENT_IGNORE) {
				// Seems it can't be allocated.
				warningstream << "Could not internalize node name \"" << nodeTrigger
					<< "\" while loading LBM \"" << lbm_def->name << "\"." << std::endl;
				continue;
			}
			c_ids.push_back(c_id);
		}

		for (content_t c_id : c_ids) {
			map[c_id].push_back(lbm_def);
		}
	}
}

const std::vector<LoadingBlockModifierDef *> *
LBMContentMapping::lookup(content_t c) const
{
	lbm_map::const_iterator it = map.find(c);
	if (it == map.end())
		return NULL;
	// This first dereferences the iterator, returning
	// a std::vector<LoadingBlockModifierDef *>
	// reference, then we convert it to a pointer.
	return &(it->second);
}

LBMManager::~LBMManager()
{
	for (auto &m_lbm_def : m_lbm_defs) {
		delete m_lbm_def.second;
	}

	for (auto &it : m_lbm_lookup) {
		(it.second).deleteContents();
	}
}

void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def)
{
	// Precondition, in query mode the map isn't used anymore
	FATAL_ERROR_IF(m_query_mode,
		"attempted to modify LBMManager in query mode");

	if (!string_allowed(lbm_def->name, LBM_NAME_ALLOWED_CHARS)) {
		throw ModError("Error adding LBM \"" + lbm_def->name +
			"\": Does not follow naming conventions: "
				"Only characters [a-z0-9_:] are allowed.");
	}

	m_lbm_defs[lbm_def->name] = lbm_def;
}

void LBMManager::loadIntroductionTimes(const std::string &times,
	IGameDef *gamedef, u32 now)
{
	m_query_mode = true;

	// name -> time map.
	// Storing it in a map first instead of
	// handling the stuff directly in the loop
	// removes all duplicate entries.
	// TODO make this std::unordered_map
	std::map<std::string, u32> introduction_times;

	/*
	The introduction times string consists of name~time entries,
	with each entry terminated by a semicolon. The time is decimal.
	 */

	size_t idx = 0;
	size_t idx_new;
	while ((idx_new = times.find(';', idx)) != std::string::npos) {
		std::string entry = times.substr(idx, idx_new - idx);
		std::vector<std::string> components = str_split(entry, '~');
		if (components.size() != 2)
			throw SerializationError("Introduction times entry \""
				+ entry + "\" requires exactly one '~'!");
		const std::string &name = components[0];
		u32 time = from_string<u32>(components[1]);
		introduction_times[name] = time;
		idx = idx_new + 1;
	}

	// Put stuff from introduction_times into m_lbm_lookup
	for (std::map<std::string, u32>::const_iterator it = introduction_times.begin();
		it != introduction_times.end(); ++it) {
		const std::string &name = it->first;
		u32 time = it->second;

		std::map<std::string, LoadingBlockModifierDef *>::iterator def_it =
			m_lbm_defs.find(name);
		if (def_it == m_lbm_defs.end()) {
			// This seems to be an LBM entry for
			// an LBM we haven't loaded. Discard it.
			continue;
		}
		LoadingBlockModifierDef *lbm_def = def_it->second;
		if (lbm_def->run_at_every_load) {
			// This seems to be an LBM entry for
			// an LBM that runs at every load.
			// Don't add it just yet.
			continue;
		}

		m_lbm_lookup[time].addLBM(lbm_def, gamedef);

		// Erase the entry so that we know later
		// what elements didn't get put into m_lbm_lookup
		m_lbm_defs.erase(name);
	}

	// Now also add the elements from m_lbm_defs to m_lbm_lookup
	// that weren't added in the previous step.
	// They are introduced first time to this world,
	// or are run at every load (introducement time hardcoded to U32_MAX).

	LBMContentMapping &lbms_we_introduce_now = m_lbm_lookup[now];
	LBMContentMapping &lbms_running_always = m_lbm_lookup[U32_MAX];

	for (auto &m_lbm_def : m_lbm_defs) {
		if (m_lbm_def.second->run_at_every_load) {
			lbms_running_always.addLBM(m_lbm_def.second, gamedef);
		} else {
			lbms_we_introduce_now.addLBM(m_lbm_def.second, gamedef);
		}
	}

	// Clear the list, so that we don't delete remaining elements
	// twice in the destructor
	m_lbm_defs.clear();
}

std::string LBMManager::createIntroductionTimesString()
{
	// Precondition, we must be in query mode
	FATAL_ERROR_IF(!m_query_mode,
		"attempted to query on non fully set up LBMManager");

	std::ostringstream oss;
	for (const auto &it : m_lbm_lookup) {
		u32 time = it.first;
		const std::vector<LoadingBlockModifierDef *> &lbm_list = it.second.lbm_list;
		for (const auto &lbm_def : lbm_list) {
			// Don't add if the LBM runs at every load,
			// then introducement time is hardcoded
			// and doesn't need to be stored
			if (lbm_def->run_at_every_load)
				continue;
			oss << lbm_def->name << "~" << time << ";";
		}
	}
	return oss.str();
}

void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp)
{
	// Precondition, we need m_lbm_lookup to be initialized
	FATAL_ERROR_IF(!m_query_mode,
		"attempted to query on non fully set up LBMManager");
	v3s16 pos_of_block = block->getPosRelative();
	v3s16 pos;
	MapNode n;
	content_t c;
	lbm_lookup_map::const_iterator it = getLBMsIntroducedAfter(stamp);
	for (; it != m_lbm_lookup.end(); ++it) {
		// Cache previous version to speedup lookup which has a very high performance
		// penalty on each call
		content_t previous_c{};
		std::vector<LoadingBlockModifierDef *> *lbm_list = nullptr;

		for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++)
			for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++)
				for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++) {
					n = block->getNodeNoEx(pos);
					c = n.getContent();

					// If content_t are not matching perform an LBM lookup
					if (previous_c != c) {
						lbm_list = (std::vector<LoadingBlockModifierDef *> *)
							it->second.lookup(c);
						previous_c = c;
					}

					if (!lbm_list)
						continue;
					for (auto lbmdef : *lbm_list) {
						lbmdef->trigger(env, pos + pos_of_block, n);
					}
				}
	}
}

/*
	ActiveBlockList
*/

void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
{
	v3s16 p;
	for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
		for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
			for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
			{
				// limit to a sphere
				if (p.getDistanceFrom(p0) <= r) {
					// Set in list
					list.insert(p);
				}
			}
}

void fillViewConeBlock(v3s16 p0,
	const s16 r,
	const v3f camera_pos,
	const v3f camera_dir,
	const float camera_fov,
	std::set<v3s16> &list)
{
	v3s16 p;
	const s16 r_nodes = r * BS * MAP_BLOCKSIZE;
	for (p.X = p0.X - r; p.X <= p0.X+r; p.X++)
	for (p.Y = p0.Y - r; p.Y <= p0.Y+r; p.Y++)
	for (p.Z = p0.Z - r; p.Z <= p0.Z+r; p.Z++) {
		if (isBlockInSight(p, camera_pos, camera_dir, camera_fov, r_nodes)) {
			list.insert(p);
		}
	}
}

void ActiveBlockList::update(std::vector<PlayerSAO*> &active_players,
	s16 active_block_range,
	s16 active_object_range,
	std::set<v3s16> &blocks_removed,
	std::set<v3s16> &blocks_added)
{
	/*
		Create the new list
	*/
	std::set<v3s16> newlist = m_forceloaded_list;
	m_abm_list = m_forceloaded_list;
	for (const PlayerSAO *playersao : active_players) {
		v3s16 pos = getNodeBlockPos(floatToInt(playersao->getBasePosition(), BS));
		fillRadiusBlock(pos, active_block_range, m_abm_list);
		fillRadiusBlock(pos, active_block_range, newlist);

		s16 player_ao_range = std::min(active_object_range, playersao->getWantedRange());
		// only do this if this would add blocks
		if (player_ao_range > active_block_range) {
			v3f camera_dir = v3f(0,0,1);
			camera_dir.rotateYZBy(playersao->getPitch());
			camera_dir.rotateXZBy(playersao->getYaw());
			fillViewConeBlock(pos,
				player_ao_range,
				playersao->getEyePosition(),
				camera_dir,
				playersao->getFov(),
				newlist);
		}
	}

	/*
		Find out which blocks on the old list are not on the new list
	*/
	// Go through old list
	for (v3s16 p : m_list) {
		// If not on new list, it's been removed
		if (newlist.find(p) == newlist.end())
			blocks_removed.insert(p);
	}

	/*
		Find out which blocks on the new list are not on the old list
	*/
	// Go through new list
	for (v3s16 p : newlist) {
		// If not on old list, it's been added
		if(m_list.find(p) == m_list.end())
			blocks_added.insert(p);
	}

	/*
		Update m_list
	*/
	m_list.clear();
	for (v3s16 p : newlist) {
		m_list.insert(p);
	}
}

/*
	ServerEnvironment
*/

ServerEnvironment::ServerEnvironment(ServerMap *map,
	ServerScripting *scriptIface, Server *server,
	const std::string &path_world):
	Environment(server),
	m_map(map),
	m_script(scriptIface),
	m_server(server),
	m_path_world(path_world)
{
	// Determine which database backend to use
	std::string conf_path = path_world + DIR_DELIM + "world.mt";
	Settings conf;
	bool succeeded = conf.readConfigFile(conf_path.c_str());
	if (!succeeded || !conf.exists("player_backend")) {
		// fall back to files
		conf.set("player_backend", "files");
		warningstream << "/!\\ You are using old player file backend. "
				<< "This backend is deprecated and will be removed in next release /!\\"
				<< std::endl << "Switching to SQLite3 or PostgreSQL is advised, "
				<< "please read http://wiki.minetest.net/Database_backends." << std::endl;

		if (!conf.updateConfigFile(conf_path.c_str())) {
			errorstream << "ServerEnvironment::ServerEnvironment(): "
				<< "Failed to update world.mt!" << std::endl;
		}
	}

	std::string name;
	conf.getNoEx("player_backend", name);
	m_player_database = openPlayerDatabase(name, path_world, conf);

	std::string auth_name = "files";
	if (conf.exists("auth_backend")) {
		conf.getNoEx("auth_backend", auth_name);
	} else {
		conf.set("auth_backend", "files");
		if (!conf.updateConfigFile(conf_path.c_str())) {
			errorstream << "ServerEnvironment::ServerEnvironment(): "
					<< "Failed to update world.mt!" << std::endl;
		}
	}
	m_auth_database = openAuthDatabase(auth_name, path_world, conf);
}

ServerEnvironment::~ServerEnvironment()
{
	// Clear active block list.
	// This makes the next one delete all active objects.
	m_active_blocks.clear();

	// Convert all objects to static and delete the active objects
	deactivateFarObjects(true);

	// Drop/delete map
	m_map->drop();

	// Delete ActiveBlockModifiers
	for (ABMWithState &m_abm : m_abms) {
		delete m_abm.abm;
	}

	// Deallocate players
	for (RemotePlayer *m_player : m_players) {
		delete m_player;
	}

	delete m_player_database;
	delete m_auth_database;
}

Map & ServerEnvironment::getMap()
{
	return *m_map;
}

ServerMap & ServerEnvironment::getServerMap()
{
	return *m_map;
}

RemotePlayer *ServerEnvironment::getPlayer(const session_t peer_id)
{
	for (RemotePlayer *player : m_players) {
		if (player->getPeerId() == peer_id)
			return player;
	}
	return NULL;
}

RemotePlayer *ServerEnvironment::getPlayer(const char* name)
{
	for (RemotePlayer *player : m_players) {
		if (strcmp(player->getName(), name) == 0)
			return player;
	}
	return NULL;
}

void ServerEnvironment::addPlayer(RemotePlayer *player)
{
	/*
		Check that peer_ids are unique.
		Also check that names are unique.
		Exception: there can be multiple players with peer_id=0
	*/
	// If peer id is non-zero, it has to be unique.
	if (player->getPeerId() != PEER_ID_INEXISTENT)
		FATAL_ERROR_IF(getPlayer(player->getPeerId()) != NULL, "Peer id not unique");
	// Name has to be unique.
	FATAL_ERROR_IF(getPlayer(player->getName()) != NULL, "Player name not unique");
	// Add.
	m_players.push_back(player);
}

void ServerEnvironment::removePlayer(RemotePlayer *player)
{
	for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
		it != m_players.end(); ++it) {
		if ((*it) == player) {
			delete *it;
			m_players.erase(it);
			return;
		}
	}
}

bool ServerEnvironment::removePlayerFromDatabase(const std::string &name)
{
	return m_player_database->removePlayer(name);
}

bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, v3s16 *p)
{
	// Iterate trough nodes on the line
	voxalgo::VoxelLineIterator iterator(pos1 / BS, (pos2 - pos1) / BS);
	do {
		MapNode n = getMap().getNodeNoEx(iterator.m_current_node_pos);

		// Return non-air
		if (n.param0 != CONTENT_AIR) {
			if (p)
				*p = iterator.m_current_node_pos;
			return false;
		}
		iterator.next();
	} while (iterator.m_current_index <= iterator.m_last_index);
	return true;
}

void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason,
	const std::string &str_reason, bool reconnect)
{
	for (RemotePlayer *player : m_players) {
		m_server->DenyAccessVerCompliant(player->getPeerId(),
			player->protocol_version, reason, str_reason, reconnect);
	}
}

void ServerEnvironment::saveLoadedPlayers()
{
	std::string players_path = m_path_world + DIR_DELIM + "players";
	fs::CreateDir(players_path);

	for (RemotePlayer *player : m_players) {
		if (player->checkModified() || (player->getPlayerSAO() &&
				player->getPlayerSAO()->getMeta().isModified())) {
			try {
				m_player_database->savePlayer(player);
			} catch (DatabaseException &e) {
				errorstream << "Failed to save player " << player->getName() << " exception: "
					<< e.what() << std::endl;
				throw;
			}
		}
	}
}

void ServerEnvironment::savePlayer(RemotePlayer *player)
{
	try {
		m_player_database->savePlayer(player);
	} catch (DatabaseException &e) {
		errorstream << "Failed to save player " << player->getName() << " exception: "
			<< e.what() << std::endl;
		throw;
	}
}

PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player,
	session_t peer_id, bool is_singleplayer)
{
	PlayerSAO *playersao = new PlayerSAO(this, player, peer_id, is_singleplayer);
	// Create player if it doesn't exist
	if (!m_player_database->loadPlayer(player, playersao)) {
		*new_player = true;
		// Set player position
		infostream << "Server: Finding spawn place for player \""
			<< player->getName() << "\"" << std::endl;
		playersao->setBasePosition(m_server->findSpawnPos());

		// Make sure the player is saved
		player->setModified(true);
	} else {
		// If the player exists, ensure that they respawn inside legal bounds
		// This fixes an assert crash when the player can't be added
		// to the environment
		if (objectpos_over_limit(playersao->getBasePosition())) {
			actionstream << "Respawn position for player \""
				<< player->getName() << "\" outside limits, resetting" << std::endl;
			playersao->setBasePosition(m_server->findSpawnPos());
		}
	}

	// Add player to environment
	addPlayer(player);

	/* Clean up old HUD elements from previous sessions */
	player->clearHud();

	/* Add object to environment */
	addActiveObject(playersao);

	return playersao;
}

void ServerEnvironment::saveMeta()
{
	std::string path = m_path_world + DIR_DELIM "env_meta.txt";

	// Open file and serialize
	std::ostringstream ss(std::ios_base::binary);

	Settings args;
	args.setU64("game_time", m_game_time);
	args.setU64("time_of_day", getTimeOfDay());
	args.setU64("last_clear_objects_time", m_last_clear_objects_time);
	args.setU64("lbm_introduction_times_version", 1);
	args.set("lbm_introduction_times",
		m_lbm_mgr.createIntroductionTimesString());
	args.setU64("day_count", m_day_count);
	args.writeLines(ss);
	ss<<"EnvArgsEnd\n";

	if(!fs::safeWriteToFile(path, ss.str()))
	{
		infostream<<"ServerEnvironment::saveMeta(): Failed to write "
			<<path<<std::endl;
		throw SerializationError("Couldn't save env meta");
	}
}

void ServerEnvironment::loadMeta()
{
	// If file doesn't exist, load default environment metadata
	if (!fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
		infostream << "ServerEnvironment: Loading default environment metadata"
			<< std::endl;
		loadDefaultMeta();
		return;
	}

	infostream << "ServerEnvironment: Loading environment metadata" << std::endl;

	std::string path = m_path_world + DIR_DELIM "env_meta.txt";

	// Open file and deserialize
	std::ifstream is(path.c_str(), std::ios_base::binary);
	if (!is.good()) {
		infostream << "ServerEnvironment::loadMeta(): Failed to open "
			<< path << std::endl;
		throw SerializationError("Couldn't load env meta");
	}

	Settings args;

	if (!args.parseConfigLines(is, "EnvArgsEnd")) {
		throw SerializationError("ServerEnvironment::loadMeta(): "
			"EnvArgsEnd not found!");
	}

	try {
		m_game_time = args.getU64("game_time");
	} catch (SettingNotFoundException &e) {
		// Getting this is crucial, otherwise timestamps are useless
		throw SerializationError("Couldn't load env meta game_time");
	}

	setTimeOfDay(args.exists("time_of_day") ?
		// set day to early morning by default
		args.getU64("time_of_day") : 5250);

	m_last_clear_objects_time = args.exists("last_clear_objects_time") ?
		// If missing, do as if clearObjects was never called
		args.getU64("last_clear_objects_time") : 0;

	std::string lbm_introduction_times;
	try {
		u64 ver = args.getU64("lbm_introduction_times_version");
		if (ver == 1) {
			lbm_introduction_times = args.get("lbm_introduction_times");
		} else {
			infostream << "ServerEnvironment::loadMeta(): Non-supported"
				<< " introduction time version " << ver << std::endl;
		}
	} catch (SettingNotFoundException &e) {
		// No problem, this is expected. Just continue with an empty string
	}
	m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_server, m_game_time);

	m_day_count = args.exists("day_count") ?
		args.getU64("day_count") : 0;
}

/**
 * called if env_meta.txt doesn't exist (e.g. new world)
 */
void ServerEnvironment::loadDefaultMeta()
{
	m_lbm_mgr.loadIntroductionTimes("", m_server, m_game_time);
}

struct ActiveABM
{
	ActiveBlockModifier *abm;
	int chance;
	std::vector<content_t> required_neighbors;
	bool check_required_neighbors; // false if required_neighbors is known to be empty
};

class ABMHandler
{
private:
	ServerEnvironment *m_env;
	std::vector<std::vector<ActiveABM> *> m_aabms;
public:
	ABMHandler(std::vector<ABMWithState> &abms,
		float dtime_s, ServerEnvironment *env,
		bool use_timers):
		m_env(env)
	{
		if(dtime_s < 0.001)
			return;
		const NodeDefManager *ndef = env->getGameDef()->ndef();
		for (ABMWithState &abmws : abms) {
			ActiveBlockModifier *abm = abmws.abm;
			float trigger_interval = abm->getTriggerInterval();
			if(trigger_interval < 0.001)
				trigger_interval = 0.001;
			float actual_interval = dtime_s;
			if(use_timers){
				abmws.timer += dtime_s;
				if(abmws.timer < trigger_interval)
					continue;
				abmws.timer -= trigger_interval;
				actual_interval = trigger_interval;
			}
			float chance = abm->getTriggerChance();
			if(chance == 0)
				chance = 1;
			ActiveABM aabm;
			aabm.abm = abm;
			if (abm->getSimpleCatchUp()) {
				float intervals = actual_interval / trigger_interval;
				if(intervals == 0)
					continue;
				aabm.chance = chance / intervals;
				if(aabm.chance == 0)
					aabm.chance = 1;
			} else {
				aabm.chance = chance;
			}

			// Trigger neighbors
			const std::vector<std::string> &required_neighbors_s =
				abm->getRequiredNeighbors();
			for (const std::string &required_neighbor_s : required_neighbors_s) {
				ndef->getIds(required_neighbor_s, aabm.required_neighbors);
			}
			aabm.check_required_neighbors = !required_neighbors_s.empty();

			// Trigger contents
			const std::vector<std::string> &contents_s = abm->getTriggerContents();
			for (const std::string &content_s : contents_s) {
				std::vector<content_t> ids;
				ndef->getIds(content_s, ids);
				for (content_t c : ids) {
					if (c >= m_aabms.size())
						m_aabms.resize(c + 256, NULL);
					if (!m_aabms[c])
						m_aabms[c] = new std::vector<ActiveABM>;
					m_aabms[c]->push_back(aabm);
				}
			}
		}
	}

	~ABMHandler()
	{
		for (auto &aabms : m_aabms)
			delete aabms;
	}

	// Find out how many objects the given block and its neighbours contain.
	// Returns the number of objects in the block, and also in 'wider' the
	// number of objects in the block and all its neighbours. The latter
	// may an estimate if any neighbours are unloaded.
	u32 countObjects(MapBlock *block, ServerMap * map, u32 &wider)
	{
		wider = 0;
		u32 wider_unknown_count = 0;
		for(s16 x=-1; x<=1; x++)
			for(s16 y=-1; y<=1; y++)
				for(s16 z=-1; z<=1; z++)
				{
					MapBlock *block2 = map->getBlockNoCreateNoEx(
						block->getPos() + v3s16(x,y,z));
					if(block2==NULL){
						wider_unknown_count++;
						continue;
					}
					wider += block2->m_static_objects.m_active.size()
						+ block2->m_static_objects.m_stored.size();
				}
		// Extrapolate
		u32 active_object_count = block->m_static_objects.m_active.size();
		u32 wider_known_count = 3*3*3 - wider_unknown_count;
		wider += wider_unknown_count * wider / wider_known_count;
		return active_object_count;

	}
	void apply(MapBlock *block, int &blocks_scanned, int &abms_run, int &blocks_cached)
	{
		if(m_aabms.empty() || block->isDummy())
			return;

		// Check the content type cache first
		// to see whether there are any ABMs
		// to be run at all for this block.
		if (block->contents_cached) {
			blocks_cached++;
			bool run_abms = false;
			for (content_t c : block->contents) {
				if (c < m_aabms.size() && m_aabms[c]) {
					run_abms = true;
					break;
				}
			}
			if (!run_abms)
				return;
		} else {
			// Clear any caching
			block->contents.clear();
		}
		blocks_scanned++;

		ServerMap *map = &m_env->getServerMap();

		u32 active_object_count_wider;
		u32 active_object_count = this->countObjects(block, map, active_object_count_wider);
		m_env->m_added_objects = 0;

		v3s16 p0;
		for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
		for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
		for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
		{
			const MapNode &n = block->getNodeUnsafe(p0);
			content_t c = n.getContent();
			// Cache content types as we go
			if (!block->contents_cached && !block->do_not_cache_contents) {
				block->contents.insert(c);
				if (block->contents.size() > 64) {
					// Too many different nodes... don't try to cache
					block->do_not_cache_contents = true;
					block->contents.clear();
				}
			}

			if (c >= m_aabms.size() || !m_aabms[c])
				continue;

			v3s16 p = p0 + block->getPosRelative();
			for (ActiveABM &aabm : *m_aabms[c]) {
				if (myrand() % aabm.chance != 0)
					continue;

				// Check neighbors
				if (aabm.check_required_neighbors) {
					v3s16 p1;
					for(p1.X = p0.X-1; p1.X <= p0.X+1; p1.X++)
					for(p1.Y = p0.Y-1; p1.Y <= p0.Y+1; p1.Y++)
					for(p1.Z = p0.Z-1; p1.Z <= p0.Z+1; p1.Z++)
					{
						if(p1 == p0)
							continue;
						content_t c;
						if (block->isValidPosition(p1)) {
							// if the neighbor is found on the same map block
							// get it straight from there
							const MapNode &n = block->getNodeUnsafe(p1);
							c = n.getContent();
						} else {
							// otherwise consult the map
							MapNode n = map->getNodeNoEx(p1 + block->getPosRelative());
							c = n.getContent();
						}
						if (CONTAINS(aabm.required_neighbors, c))
							goto neighbor_found;
					}
					// No required neighbor found
					continue;
				}
				neighbor_found:

				abms_run++;
				// Call all the trigger variations
				aabm.abm->trigger(m_env, p, n);
				aabm.abm->trigger(m_env, p, n,
					active_object_count, active_object_count_wider);

				// Count surrounding objects again if the abms added any
				if(m_env->m_added_objects > 0) {
					active_object_count = countObjects(block, map, active_object_count_wider);
					m_env->m_added_objects = 0;
				}
			}
		}
		block->contents_cached = !block->do_not_cache_contents;
	}
};

void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
{
	// Reset usage timer immediately, otherwise a block that becomes active
	// again at around the same time as it would normally be unloaded will
	// get unloaded incorrectly. (I think this still leaves a small possibility
	// of a race condition between this and server::AsyncRunStep, which only
	// some kind of synchronisation will fix, but it at least reduces the window
	// of opportunity for it to break from seconds to nanoseconds)
	block->resetUsageTimer();

	// Get time difference
	u32 dtime_s = 0;
	u32 stamp = block->getTimestamp();
	if (m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
		dtime_s = m_game_time - stamp;
	dtime_s += additional_dtime;

	/*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
			<<stamp<<", game time: "<<m_game_time<<std::endl;*/

	// Remove stored static objects if clearObjects was called since block's timestamp
	if (stamp == BLOCK_TIMESTAMP_UNDEFINED || stamp < m_last_clear_objects_time) {
		block->m_static_objects.m_stored.clear();
		// do not set changed flag to avoid unnecessary mapblock writes
	}

	// Set current time as timestamp
	block->setTimestampNoChangedFlag(m_game_time);

	/*infostream<<"ServerEnvironment::activateBlock(): block is "
			<<dtime_s<<" seconds old."<<std::endl;*/

	// Activate stored objects
	activateObjects(block, dtime_s);

	/* Handle LoadingBlockModifiers */
	m_lbm_mgr.applyLBMs(this, block, stamp);

	// Run node timers
	std::vector<NodeTimer> elapsed_timers =
		block->m_node_timers.step((float)dtime_s);
	if (!elapsed_timers.empty()) {
		MapNode n;
		for (const NodeTimer &elapsed_timer : elapsed_timers) {
			n = block->getNodeNoEx(elapsed_timer.position);
			v3s16 p = elapsed_timer.position + block->getPosRelative();
			if (m_script->node_on_timer(p, n, elapsed_timer.elapsed))
				block->setNodeTimer(NodeTimer(elapsed_timer.timeout, 0,
					elapsed_timer.position));
		}
	}
}

void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
{
	m_abms.emplace_back(abm);
}

void ServerEnvironment::addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm)
{
	m_lbm_mgr.addLBMDef(lbm);
}

bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
{
	const NodeDefManager *ndef = m_server->ndef();
	MapNode n_old = m_map->getNodeNoEx(p);

	const ContentFeatures &cf_old = ndef->get(n_old);

	// Call destructor
	if (cf_old.has_on_destruct)
		m_script->node_on_destruct(p, n_old);

	// Replace node
	if (!m_map->addNodeWithEvent(p, n))
		return false;

	// Update active VoxelManipulator if a mapgen thread
	m_map->updateVManip(p);

	// Call post-destructor
	if (cf_old.has_after_destruct)
		m_script->node_after_destruct(p, n_old);

	// Retrieve node content features
	// if new node is same as old, reuse old definition to prevent a lookup
	const ContentFeatures &cf_new = n_old == n ? cf_old : ndef->get(n);

	// Call constructor
	if (cf_new.has_on_construct)
		m_script->node_on_construct(p, n);

	return true;
}

bool ServerEnvironment::removeNode(v3s16 p)
{
	const NodeDefManager *ndef = m_server->ndef();
	MapNode n_old = m_map->getNodeNoEx(p);

	// Call destructor
	if (ndef->get(n_old).has_on_destruct)
		m_script->node_on_destruct(p, n_old);

	// Replace with air
	// This is slightly optimized compared to addNodeWithEvent(air)
	if (!m_map->removeNodeWithEvent(p))
		return false;

	// Update active VoxelManipulator if a mapgen thread
	m_map->updateVManip(p);

	// Call post-destructor
	if (ndef->get(n_old).has_after_destruct)
		m_script->node_after_destruct(p, n_old);

	// Air doesn't require constructor
	return true;
}

bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
{
	if (!m_map->addNodeWithEvent(p, n, false))
		return false;

	// Update active VoxelManipulator if a mapgen thread
	m_map->updateVManip(p);

	return true;
}

void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f pos,
	float radius)
{
	for (auto &activeObject : m_active_objects) {
		ServerActiveObject* obj = activeObject.second;
		u16 id = activeObject.first;
		v3f objectpos = obj->getBasePosition();
		if (objectpos.getDistanceFrom(pos) > radius)
			continue;
		objects.push_back(id);
	}
}

void ServerEnvironment::clearObjects(ClearObjectsMode mode)
{
	infostream << "ServerEnvironment::clearObjects(): "
		<< "Removing all active objects" << std::endl;
	std::vector<u16> objects_to_remove;
	for (auto &it : m_active_objects) {
		u16 id = it.first;
		ServerActiveObject* obj = it.second;
		if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
			continue;

		// Delete static object if block is loaded
		deleteStaticFromBlock(obj, id, MOD_REASON_CLEAR_ALL_OBJECTS, true);

		// If known by some client, don't delete immediately
		if (obj->m_known_by_count > 0) {
			obj->m_pending_removal = true;
			continue;
		}

		// Tell the object about removal
		obj->removingFromEnvironment();
		// Deregister in scripting api
		m_script->removeObjectReference(obj);

		// Delete active object
		if (obj->environmentDeletes())
			delete obj;
		// Id to be removed from m_active_objects
		objects_to_remove.push_back(id);
	}

	// Remove references from m_active_objects
	for (u16 i : objects_to_remove) {
		m_active_objects.erase(i);
	}

	// Get list of loaded blocks
	std::vector<v3s16> loaded_blocks;
	infostream << "ServerEnvironment::clearObjects(): "
		<< "Listing all loaded blocks" << std::endl;
	m_map->listAllLoadedBlocks(loaded_blocks);
	infostream << "ServerEnvironment::clearObjects(): "
		<< "Done listing all loaded blocks: "
		<< loaded_blocks.size()<<std::endl;

	// Get list of loadable blocks
	std::vector<v3s16> loadable_blocks;
	if (mode == CLEAR_OBJECTS_MODE_FULL) {
		infostream << "ServerEnvironment::clearObjects(): "
			<< "Listing all loadable blocks" << std::endl;
		m_map->listAllLoadableBlocks(loadable_blocks);
		infostream << "ServerEnvironment::clearObjects(): "
			<< "Done listing all loadable blocks: "
			<< loadable_blocks.size() << std::endl;
	} else {
		loadable_blocks = loaded_blocks;
	}

	actionstream << "ServerEnvironment::clearObjects(): "
		<< "Now clearing objects in " << loadable_blocks.size()
		<< " blocks" << std::endl;

	// Grab a reference on each loaded block to avoid unloading it
	for (v3s16 p : loaded_blocks) {
		MapBlock *block = m_map->getBlockNoCreateNoEx(p);
		assert(block != NULL);
		block->refGrab();
	}

	// Remove objects in all loadable blocks
	u32 unload_interval = U32_MAX;
	if (mode == CLEAR_OBJECTS_MODE_FULL) {
		unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
		unload_interval = MYMAX(unload_interval, 1);
	}
	u32 report_interval = loadable_blocks.size() / 10;
	u32 num_blocks_checked = 0;
	u32 num_blocks_cleared = 0;
	u32 num_objs_cleared = 0;
	for (auto i = loadable_blocks.begin();
		i != loadable_blocks.end(); ++i) {
		v3s16 p = *i;
		MapBlock *block = m_map->emergeBlock(p, false);
		if (!block) {
			errorstream << "ServerEnvironment::clearObjects(): "
				<< "Failed to emerge block " << PP(p) << std::endl;
			continue;
		}
		u32 num_stored = block->m_static_objects.m_stored.size();
		u32 num_active = block->m_static_objects.m_active.size();
		if (num_stored != 0 || num_active != 0) {
			block->m_static_objects.m_stored.clear();
			block->m_static_objects.m_active.clear();
			block->raiseModified(MOD_STATE_WRITE_NEEDED,
				MOD_REASON_CLEAR_ALL_OBJECTS);
			num_objs_cleared += num_stored + num_active;
			num_blocks_cleared++;
		}
		num_blocks_checked++;

		if (report_interval != 0 &&
			num_blocks_checked % report_interval == 0) {
			float percent = 100.0 * (float)num_blocks_checked /
				loadable_blocks.size();
			actionstream << "ServerEnvironment::clearObjects(): "
				<< "Cleared " << num_objs_cleared << " objects"
				<< " in " << num_blocks_cleared << " blocks ("
				<< percent << "%)" << std::endl;
		}
		if (num_blocks_checked % unload_interval == 0) {
			m_map->unloadUnreferencedBlocks();
		}
	}
	m_map->unloadUnreferencedBlocks();

	// Drop references that were added above
	for (v3s16 p : loaded_blocks) {
		MapBlock *block = m_map->getBlockNoCreateNoEx(p);
		assert(block);
		block->refDrop();
	}

	m_last_clear_objects_time = m_game_time;

	actionstream << "ServerEnvironment::clearObjects(): "
		<< "Finished: Cleared " << num_objs_cleared << " objects"
		<< " in " << num_blocks_cleared << " blocks" << std::endl;
}

void ServerEnvironment::step(float dtime)
{
	/* Step time of day */
	stepTimeOfDay(dtime);

	// Update this one
	// NOTE: This is kind of funny on a singleplayer game, but doesn't
	// really matter that much.
	static thread_local const float server_step =
			g_settings->getFloat("dedicated_server_step");
	m_recommended_send_interval = server_step;

	/*
		Increment game time
	*/
	{
		m_game_time_fraction_counter += dtime;
		u32 inc_i = (u32)m_game_time_fraction_counter;
		m_game_time += inc_i;
		m_game_time_fraction_counter -= (float)inc_i;
	}

	/*
		Handle players
	*/
	{
		ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
		for (RemotePlayer *player : m_players) {
			// Ignore disconnected players
			if (player->getPeerId() == PEER_ID_INEXISTENT)
				continue;

			// Move
			player->move(dtime, this, 100 * BS);
		}
	}

	/*
		Manage active block list
	*/
	if (m_active_blocks_management_interval.step(dtime, m_cache_active_block_mgmt_interval)) {
		ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg per interval", SPT_AVG);
		/*
			Get player block positions
		*/
		std::vector<PlayerSAO*> players;
		for (RemotePlayer *player: m_players) {
			// Ignore disconnected players
			if (player->getPeerId() == PEER_ID_INEXISTENT)
				continue;

			PlayerSAO *playersao = player->getPlayerSAO();
			assert(playersao);

			players.push_back(playersao);
		}

		/*
			Update list of active blocks, collecting changes
		*/
		// use active_object_send_range_blocks since that is max distance
		// for active objects sent the client anyway
		static thread_local const s16 active_object_range =
				g_settings->getS16("active_object_send_range_blocks");
		static thread_local const s16 active_block_range =
				g_settings->getS16("active_block_range");
		std::set<v3s16> blocks_removed;
		std::set<v3s16> blocks_added;
		m_active_blocks.update(players, active_block_range, active_object_range,
			blocks_removed, blocks_added);

		/*
			Handle removed blocks
		*/

		// Convert active objects that are no more in active blocks to static
		deactivateFarObjects(false);

		for (const v3s16 &p: blocks_removed) {
			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if (!block)
				continue;

			// Set current time as timestamp (and let it set ChangedFlag)
			block->setTimestamp(m_game_time);
		}

		/*
			Handle added blocks
		*/

		for (const v3s16 &p: blocks_added) {
			MapBlock *block = m_map->getBlockOrEmerge(p);
			if (!block) {
				m_active_blocks.m_list.erase(p);
				m_active_blocks.m_abm_list.erase(p);
				continue;
			}

			activateBlock(block);
		}
	}

	/*
		Mess around in active blocks
	*/
	if (m_active_blocks_nodemetadata_interval.step(dtime, m_cache_nodetimer_interval)) {
		ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg per interval", SPT_AVG);

		float dtime = m_cache_nodetimer_interval;

		for (const v3s16 &p: m_active_blocks.m_list) {
			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if (!block)
				continue;

			// Reset block usage timer
			block->resetUsageTimer();

			// Set current time as timestamp
			block->setTimestampNoChangedFlag(m_game_time);
			// If time has changed much from the one on disk,
			// set block to be saved when it is unloaded
			if(block->getTimestamp() > block->getDiskTimestamp() + 60)
				block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
					MOD_REASON_BLOCK_EXPIRED);

			// Run node timers
			std::vector<NodeTimer> elapsed_timers = block->m_node_timers.step(dtime);
			if (!elapsed_timers.empty()) {
				MapNode n;
				v3s16 p2;
				for (const NodeTimer &elapsed_timer: elapsed_timers) {
					n = block->getNodeNoEx(elapsed_timer.position);
					p2 = elapsed_timer.position + block->getPosRelative();
					if (m_script->node_on_timer(p2, n, elapsed_timer.elapsed)) {
						block->setNodeTimer(NodeTimer(
							elapsed_timer.timeout, 0, elapsed_timer.position));
					}
				}
			}
		}
	}

	if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval))
		do { // breakable
			if (m_active_block_interval_overload_skip > 0) {
				ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
				m_active_block_interval_overload_skip--;
				break;
			}
			ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG);
			TimeTaker timer("modify in active blocks per interval");

			// Initialize handling of ActiveBlockModifiers
			ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true);

			int blocks_scanned = 0;
			int abms_run = 0;
			int blocks_cached = 0;
			for (const v3s16 &p : m_active_blocks.m_abm_list) {
				MapBlock *block = m_map->getBlockNoCreateNoEx(p);
				if (!block)
					continue;

				// Set current time as timestamp
				block->setTimestampNoChangedFlag(m_game_time);

				/* Handle ActiveBlockModifiers */
				abmhandler.apply(block, blocks_scanned, abms_run, blocks_cached);
			}
			g_profiler->avg("SEnv: active blocks", m_active_blocks.m_abm_list.size());
			g_profiler->avg("SEnv: active blocks cached", blocks_cached);
			g_profiler->avg("SEnv: active blocks scanned for ABMs", blocks_scanned);
			g_profiler->avg("SEnv: ABMs run", abms_run);

			u32 time_ms = timer.stop(true);
			u32 max_time_ms = 200;
			if (time_ms > max_time_ms) {
				warningstream<<"active block modifiers took "
					<<time_ms<<"ms (longer than "
					<<max_time_ms<<"ms)"<<std::endl;
				m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
			}
		}while(0);

	/*
		Step script environment (run global on_step())
	*/
	m_script->environment_Step(dtime);

	/*
		Step active objects
	*/
	{
		ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
		//TimeTaker timer("Step active objects");

		g_profiler->avg("SEnv: num of objects", m_active_objects.size());

		// This helps the objects to send data at the same time
		bool send_recommended = false;
		m_send_recommended_timer += dtime;
		if(m_send_recommended_timer > getSendRecommendedInterval())
		{
			m_send_recommended_timer -= getSendRecommendedInterval();
			send_recommended = true;
		}

		for (auto &ao_it : m_active_objects) {
			ServerActiveObject* obj = ao_it.second;
			if (obj->isGone())
				continue;

			// Step object
			obj->step(dtime, send_recommended);
			// Read messages from object
			while (!obj->m_messages_out.empty()) {
				m_active_object_messages.push(obj->m_messages_out.front());
				obj->m_messages_out.pop();
			}
		}
	}

	/*
		Manage active objects
	*/
	if (m_object_management_interval.step(dtime, 0.5)) {
		ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
		removeRemovedObjects();
	}

	/*
		Manage particle spawner expiration
	*/
	if (m_particle_management_interval.step(dtime, 1.0)) {
		for (std::unordered_map<u32, float>::iterator i = m_particle_spawners.begin();
			i != m_particle_spawners.end(); ) {
			//non expiring spawners
			if (i->second == PARTICLE_SPAWNER_NO_EXPIRY) {
				++i;
				continue;
			}

			i->second -= 1.0f;
			if (i->second <= 0.f)
				m_particle_spawners.erase(i++);
			else
				++i;
		}
	}
}

u32 ServerEnvironment::addParticleSpawner(float exptime)
{
	// Timers with lifetime 0 do not expire
	float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY;

	u32 id = 0;
	for (;;) { // look for unused particlespawner id
		id++;
		std::unordered_map<u32, float>::iterator f = m_particle_spawners.find(id);
		if (f == m_particle_spawners.end()) {
			m_particle_spawners[id] = time;
			break;
		}
	}
	return id;
}

u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id)
{
	u32 id = addParticleSpawner(exptime);
	m_particle_spawner_attachments[id] = attached_id;
	if (ServerActiveObject *obj = getActiveObject(attached_id)) {
		obj->attachParticleSpawner(id);
	}
	return id;
}

void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object)
{
	m_particle_spawners.erase(id);
	const auto &it = m_particle_spawner_attachments.find(id);
	if (it != m_particle_spawner_attachments.end()) {
		u16 obj_id = it->second;
		ServerActiveObject *sao = getActiveObject(obj_id);
		if (sao != NULL && remove_from_object) {
			sao->detachParticleSpawner(id);
		}
		m_particle_spawner_attachments.erase(id);
	}
}

ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
{
	ServerActiveObjectMap::const_iterator n = m_active_objects.find(id);
	return (n != m_active_objects.end() ? n->second : NULL);
}

/**
 * Verify if id is a free active object id
 * @param id
 * @return true if slot is free
 */
bool ServerEnvironment::isFreeServerActiveObjectId(u16 id) const
{
	if (id == 0)
		return false;

	return m_active_objects.find(id) == m_active_objects.end();
}

/**
 * Retrieve the first free ActiveObject ID
 * @return free activeobject ID or 0 if none was found
 */
u16 ServerEnvironment::getFreeServerActiveObjectId()
{
	// try to reuse id's as late as possible
	static u16 last_used_id = 0;
	u16 startid = last_used_id;
	for (;;) {
		last_used_id++;
		if (isFreeServerActiveObjectId(last_used_id))
			return last_used_id;

		if (last_used_id == startid)
			return 0;
	}
}

u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
{
	assert(object);	// Pre-condition
	m_added_objects++;
	u16 id = addActiveObjectRaw(object, true, 0);
	return id;
}

/*
	Finds out what new objects have been added to
	inside a radius around a position
*/
void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
	s16 player_radius,
	std::set<u16> &current_objects,
	std::queue<u16> &added_objects)
{
	f32 radius_f = radius * BS;
	f32 player_radius_f = player_radius * BS;

	if (player_radius_f < 0)
		player_radius_f = 0;
	/*
		Go through the object list,
		- discard removed/deactivated objects,
		- discard objects that are too far away,
		- discard objects that are found in current_objects.
		- add remaining objects to added_objects
	*/
	for (auto &ao_it : m_active_objects) {
		u16 id = ao_it.first;

		// Get object
		ServerActiveObject *object = ao_it.second;
		if (object == NULL)
			continue;

		if (object->isGone())
			continue;

		f32 distance_f = object->getBasePosition().
			getDistanceFrom(playersao->getBasePosition());
		if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
			// Discard if too far
			if (distance_f > player_radius_f && player_radius_f != 0)
				continue;
		} else if (distance_f > radius_f)
			continue;

		// Discard if already on current_objects
		std::set<u16>::iterator n;
		n = current_objects.find(id);
		if(n != current_objects.end())
			continue;
		// Add to added_objects
		added_objects.push(id);
	}
}

/*
	Finds out what objects have been removed from
	inside a radius around a position
*/
void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius,
	s16 player_radius,
	std::set<u16> &current_objects,
	std::queue<u16> &removed_objects)
{
	f32 radius_f = radius * BS;
	f32 player_radius_f = player_radius * BS;

	if (player_radius_f < 0)
		player_radius_f = 0;
	/*
		Go through current_objects; object is removed if:
		- object is not found in m_active_objects (this is actually an
		  error condition; objects should be removed only after all clients
		  have been informed about removal), or
		- object is to be removed or deactivated, or
		- object is too far away
	*/
	for (u16 id : current_objects) {
		ServerActiveObject *object = getActiveObject(id);

		if (object == NULL) {
			infostream << "ServerEnvironment::getRemovedActiveObjects():"
				<< " object in current_objects is NULL" << std::endl;
			removed_objects.push(id);
			continue;
		}

		if (object->isGone()) {
			removed_objects.push(id);
			continue;
		}

		f32 distance_f = object->getBasePosition().getDistanceFrom(playersao->getBasePosition());
		if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
			if (distance_f <= player_radius_f || player_radius_f == 0)
				continue;
		} else if (distance_f <= radius_f)
			continue;

		// Object is no longer visible
		removed_objects.push(id);
	}
}

void ServerEnvironment::setStaticForActiveObjectsInBlock(
	v3s16 blockpos, bool static_exists, v3s16 static_block)
{
	MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
	if (!block)
		return;

	for (auto &so_it : block->m_static_objects.m_active) {
		// Get the ServerActiveObject counterpart to this StaticObject
		ServerActiveObjectMap::const_iterator ao_it = m_active_objects.find(so_it.first);
		if (ao_it == m_active_objects.end()) {
			// If this ever happens, there must be some kind of nasty bug.
			errorstream << "ServerEnvironment::setStaticForObjectsInBlock(): "
				"Object from MapBlock::m_static_objects::m_active not found "
				"in m_active_objects";
			continue;
		}

		ServerActiveObject *sao = ao_it->second;
		sao->m_static_exists = static_exists;
		sao->m_static_block  = static_block;
	}
}

ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
{
	if(m_active_object_messages.empty())
		return ActiveObjectMessage(0);

	ActiveObjectMessage message = m_active_object_messages.front();
	m_active_object_messages.pop();
	return message;
}

void ServerEnvironment::getSelectedActiveObjects(
	const core::line3d<f32> &shootline_on_map,
	std::vector<PointedThing> &objects)
{
	std::vector<u16> objectIds;
	getObjectsInsideRadius(objectIds, shootline_on_map.start,
		shootline_on_map.getLength() + 10.0f);
	const v3f line_vector = shootline_on_map.getVector();

	for (u16 objectId : objectIds) {
		ServerActiveObject* obj = getActiveObject(objectId);

		aabb3f selection_box;
		if (!obj->getSelectionBox(&selection_box))
			continue;

		v3f pos = obj->getBasePosition();

		aabb3f offsetted_box(selection_box.MinEdge + pos,
			selection_box.MaxEdge + pos);

		v3f current_intersection;
		v3s16 current_normal;
		if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
				&current_intersection, &current_normal)) {
			objects.emplace_back(
				(s16) objectId, current_intersection, current_normal,
				(current_intersection - shootline_on_map.start).getLengthSQ());
		}
	}
}

/*
	************ Private methods *************
*/

u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
	bool set_changed, u32 dtime_s)
{
	assert(object); // Pre-condition
	if(object->getId() == 0){
		u16 new_id = getFreeServerActiveObjectId();
		if(new_id == 0)
		{
			errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
				<<"no free ids available"<<std::endl;
			if(object->environmentDeletes())
				delete object;
			return 0;
		}
		object->setId(new_id);
	}
	else{
		verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
			<<"supplied with id "<<object->getId()<<std::endl;
	}

	if(!isFreeServerActiveObjectId(object->getId())) {
		errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
			<<"id is not free ("<<object->getId()<<")"<<std::endl;
		if(object->environmentDeletes())
			delete object;
		return 0;
	}

	if (objectpos_over_limit(object->getBasePosition())) {
		v3f p = object->getBasePosition();
		warningstream << "ServerEnvironment::addActiveObjectRaw(): "
			<< "object position (" << p.X << "," << p.Y << "," << p.Z
			<< ") outside maximum range" << std::endl;
		if (object->environmentDeletes())
			delete object;
		return 0;
	}

	/*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
			<<"added (id="<<object->getId()<<")"<<std::endl;*/

	m_active_objects[object->getId()] = object;

	verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
		<<"Added id="<<object->getId()<<"; there are now "
		<<m_active_objects.size()<<" active objects."
		<<std::endl;

	// Register reference in scripting api (must be done before post-init)
	m_script->addObjectReference(object);
	// Post-initialize object
	object->addedToEnvironment(dtime_s);

	// Add static data to block
	if(object->isStaticAllowed())
	{
		// Add static object to active static list of the block
		v3f objectpos = object->getBasePosition();
		StaticObject s_obj(object, objectpos);
		// Add to the block where the object is located in
		v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
		MapBlock *block = m_map->emergeBlock(blockpos);
		if(block){
			block->m_static_objects.m_active[object->getId()] = s_obj;
			object->m_static_exists = true;
			object->m_static_block = blockpos;

			if(set_changed)
				block->raiseModified(MOD_STATE_WRITE_NEEDED,
					MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
		} else {
			v3s16 p = floatToInt(objectpos, BS);
			errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
				<<"could not emerge block for storing id="<<object->getId()
				<<" statically (pos="<<PP(p)<<")"<<std::endl;
		}
	}

	return object->getId();
}

/*
	Remove objects that satisfy (isGone() && m_known_by_count==0)
*/
void ServerEnvironment::removeRemovedObjects()
{
	std::vector<u16> objects_to_remove;
	for (auto &ao_it : m_active_objects) {
		u16 id = ao_it.first;
		ServerActiveObject* obj = ao_it.second;

		// This shouldn't happen but check it
		if (!obj) {
			errorstream << "ServerEnvironment::removeRemovedObjects(): "
					<< "NULL object found. id=" << id << std::endl;
			objects_to_remove.push_back(id);
			continue;
		}

		/*
			We will handle objects marked for removal or deactivation
		*/
		if (!obj->isGone())
			continue;

		/*
			Delete static data from block if removed
		*/
		if (obj->m_pending_removal)
			deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);

		// If still known by clients, don't actually remove. On some future
		// invocation this will be 0, which is when removal will continue.
		if(obj->m_known_by_count > 0)
			continue;

		/*
			Move static data from active to stored if deactivated
		*/
		if (!obj->m_pending_removal && obj->m_static_exists) {
			MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
			if (block) {
				std::map<u16, StaticObject>::iterator i =
					block->m_static_objects.m_active.find(id);
				if (i != block->m_static_objects.m_active.end()) {
					block->m_static_objects.m_stored.push_back(i->second);
					block->m_static_objects.m_active.erase(id);
					block->raiseModified(MOD_STATE_WRITE_NEEDED,
						MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
				} else {
					warningstream << "ServerEnvironment::removeRemovedObjects(): "
							<< "id=" << id << " m_static_exists=true but "
							<< "static data doesn't actually exist in "
							<< PP(obj->m_static_block) << std::endl;
				}
			} else {
				infostream << "Failed to emerge block from which an object to "
						<< "be deactivated was loaded from. id=" << id << std::endl;
			}
		}

		// Tell the object about removal
		obj->removingFromEnvironment();
		// Deregister in scripting api
		m_script->removeObjectReference(obj);

		// Delete
		if(obj->environmentDeletes())
			delete obj;

		objects_to_remove.push_back(id);
	}
	// Remove references from m_active_objects
	for (u16 i : objects_to_remove) {
		m_active_objects.erase(i);
	}
}

static void print_hexdump(std::ostream &o, const std::string &data)
{
	const int linelength = 16;
	for(int l=0; ; l++){
		int i0 = linelength * l;
		bool at_end = false;
		int thislinelength = linelength;
		if(i0 + thislinelength > (int)data.size()){
			thislinelength = data.size() - i0;
			at_end = true;
		}
		for(int di=0; di<linelength; di++){
			int i = i0 + di;
			char buf[4];
			if(di<thislinelength)
				porting::mt_snprintf(buf, sizeof(buf), "%.2x ", data[i]);
			else
				porting::mt_snprintf(buf, sizeof(buf), "   ");
			o<<buf;
		}
		o<<" ";
		for(int di=0; di<thislinelength; di++){
			int i = i0 + di;
			if(data[i] >= 32)
				o<<data[i];
			else
				o<<".";
		}
		o<<std::endl;
		if(at_end)
			break;
	}
}

/*
	Convert stored objects from blocks near the players to active.
*/
void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
{
	if(block == NULL)
		return;

	// Ignore if no stored objects (to not set changed flag)
	if(block->m_static_objects.m_stored.empty())
		return;

	verbosestream<<"ServerEnvironment::activateObjects(): "
		<<"activating objects of block "<<PP(block->getPos())
		<<" ("<<block->m_static_objects.m_stored.size()
		<<" objects)"<<std::endl;
	bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
	if (large_amount) {
		errorstream<<"suspiciously large amount of objects detected: "
			<<block->m_static_objects.m_stored.size()<<" in "
			<<PP(block->getPos())
			<<"; removing all of them."<<std::endl;
		// Clear stored list
		block->m_static_objects.m_stored.clear();
		block->raiseModified(MOD_STATE_WRITE_NEEDED,
			MOD_REASON_TOO_MANY_OBJECTS);
		return;
	}

	// Activate stored objects
	std::vector<StaticObject> new_stored;
	for (const StaticObject &s_obj : block->m_static_objects.m_stored) {
		// Create an active object from the data
		ServerActiveObject *obj = ServerActiveObject::create
			((ActiveObjectType) s_obj.type, this, 0, s_obj.pos, s_obj.data);
		// If couldn't create object, store static data back.
		if(obj == NULL) {
			errorstream<<"ServerEnvironment::activateObjects(): "
				<<"failed to create active object from static object "
				<<"in block "<<PP(s_obj.pos/BS)
				<<" type="<<(int)s_obj.type<<" data:"<<std::endl;
			print_hexdump(verbosestream, s_obj.data);

			new_stored.push_back(s_obj);
			continue;
		}
		verbosestream<<"ServerEnvironment::activateObjects(): "
			<<"activated static object pos="<<PP(s_obj.pos/BS)
			<<" type="<<(int)s_obj.type<<std::endl;
		// This will also add the object to the active static list
		addActiveObjectRaw(obj, false, dtime_s);
	}

	// Clear stored list
	block->m_static_objects.m_stored.clear();
	// Add leftover failed stuff to stored list
	for (const StaticObject &s_obj : new_stored) {
		block->m_static_objects.m_stored.push_back(s_obj);
	}

	/*
		Note: Block hasn't really been modified here.
		The objects have just been activated and moved from the stored
		static list to the active static list.
		As such, the block is essentially the same.
		Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
		Otherwise there would be a huge amount of unnecessary I/O.
	*/
}

/*
	Convert objects that are not standing inside active blocks to static.

	If m_known_by_count != 0, active object is not deleted, but static
	data is still updated.

	If force_delete is set, active object is deleted nevertheless. It
	shall only be set so in the destructor of the environment.

	If block wasn't generated (not in memory or on disk),
*/
void ServerEnvironment::deactivateFarObjects(bool _force_delete)
{
	std::vector<u16> objects_to_remove;
	for (auto &ao_it : m_active_objects) {
		// force_delete might be overriden per object
		bool force_delete = _force_delete;

		ServerActiveObject* obj = ao_it.second;
		assert(obj);

		// Do not deactivate if static data creation not allowed
		if(!force_delete && !obj->isStaticAllowed())
			continue;

		// removeRemovedObjects() is responsible for these
		if(!force_delete && obj->isGone())
			continue;

		u16 id = ao_it.first;
		v3f objectpos = obj->getBasePosition();

		// The block in which the object resides in
		v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));

		// If object's static data is stored in a deactivated block and object
		// is actually located in an active block, re-save to the block in
		// which the object is actually located in.
		if(!force_delete &&
			obj->m_static_exists &&
			!m_active_blocks.contains(obj->m_static_block) &&
			m_active_blocks.contains(blockpos_o))
		{
			// Delete from block where object was located
			deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);

			StaticObject s_obj(obj, objectpos);
			// Save to block where object is located
			saveStaticToBlock(blockpos_o, id, obj, s_obj, MOD_REASON_STATIC_DATA_ADDED);

			continue;
		}

		// If block is still active, don't remove
		if(!force_delete && m_active_blocks.contains(blockpos_o))
			continue;

		verbosestream << "ServerEnvironment::deactivateFarObjects(): "
				<< "deactivating object id=" << id << " on inactive block "
				<< PP(blockpos_o) << std::endl;

		// If known by some client, don't immediately delete.
		bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);

		/*
			Update the static data
		*/
		if (obj->isStaticAllowed()) {
			// Create new static object
			StaticObject s_obj(obj, objectpos);

			bool stays_in_same_block = false;
			bool data_changed = true;

			// Check if static data has changed considerably
			if (obj->m_static_exists) {
				if (obj->m_static_block == blockpos_o)
					stays_in_same_block = true;

				MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);

				if (block) {
					std::map<u16, StaticObject>::iterator n =
						block->m_static_objects.m_active.find(id);
					if (n != block->m_static_objects.m_active.end()) {
						StaticObject static_old = n->second;

						float save_movem = obj->getMinimumSavedMovement();

						if (static_old.data == s_obj.data &&
							(static_old.pos - objectpos).getLength() < save_movem)
							data_changed = false;
					} else {
						warningstream << "ServerEnvironment::deactivateFarObjects(): "
								<< "id=" << id << " m_static_exists=true but "
								<< "static data doesn't actually exist in "
								<< PP(obj->m_static_block) << std::endl;
					}
				}
			}

			/*
				While changes are always saved, blocks are only marked as modified
				if the object has moved or different staticdata. (see above)
			*/
			bool shall_be_written = (!stays_in_same_block || data_changed);
			u32 reason = shall_be_written ? MOD_REASON_STATIC_DATA_CHANGED : MOD_REASON_UNKNOWN;

			// Delete old static object
			deleteStaticFromBlock(obj, id, reason, false);

			// Add to the block where the object is located in
			v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
			u16 store_id = pending_delete ? id : 0;
			if (!saveStaticToBlock(blockpos, store_id, obj, s_obj, reason))
				force_delete = true;
		}

		/*
			If known by some client, set pending deactivation.
			Otherwise delete it immediately.
		*/
		if(pending_delete && !force_delete)
		{
			verbosestream << "ServerEnvironment::deactivateFarObjects(): "
					<< "object id=" << id << " is known by clients"
					<< "; not deleting yet" << std::endl;

			obj->m_pending_deactivation = true;
			continue;
		}
		verbosestream << "ServerEnvironment::deactivateFarObjects(): "
				<< "object id=" << id << " is not known by clients"
				<< "; deleting" << std::endl;

		// Tell the object about removal
		obj->removingFromEnvironment();
		// Deregister in scripting api
		m_script->removeObjectReference(obj);

		// Delete active object
		if(obj->environmentDeletes())
			delete obj;
		// Id to be removed from m_active_objects
		objects_to_remove.push_back(id);
	}

	// Remove references from m_active_objects
	for (u16 i : objects_to_remove) {
		m_active_objects.erase(i);
	}
}

void ServerEnvironment::deleteStaticFromBlock(
		ServerActiveObject *obj, u16 id, u32 mod_reason, bool no_emerge)
{
	if (!obj->m_static_exists)
		return;

	MapBlock *block;
	if (no_emerge)
		block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
	else
		block = m_map->emergeBlock(obj->m_static_block, false);
	if (!block) {
		if (!no_emerge)
			errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
					<< " when deleting static data of object from it. id=" << id << std::endl;
		return;
	}

	block->m_static_objects.remove(id);
	if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
		block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);

	obj->m_static_exists = false;
}

bool ServerEnvironment::saveStaticToBlock(
		v3s16 blockpos, u16 store_id,
		ServerActiveObject *obj, const StaticObject &s_obj,
		u32 mod_reason)
{
	MapBlock *block = nullptr;
	try {
		block = m_map->emergeBlock(blockpos);
	} catch (InvalidPositionException &e) {
		// Handled via NULL pointer
		// NOTE: emergeBlock's failure is usually determined by it
		//       actually returning NULL
	}

	if (!block) {
		errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
				<< " when saving static data of object to it. id=" << store_id << std::endl;
		return false;
	}
	if (block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")) {
		warningstream << "ServerEnv: Trying to store id = " << store_id
				<< " statically but block " << PP(blockpos)
				<< " already contains "
				<< block->m_static_objects.m_stored.size()
				<< " objects." << std::endl;
		return false;
	}

	block->m_static_objects.insert(store_id, s_obj);
	if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
		block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);