mirror of
https://github.com/encounter/dynmap.git
synced 2026-03-30 11:08:39 -07:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4152337568 | |||
| c393eec159 | |||
| e724a7bccb | |||
| 97ff6a2c2d | |||
| 33206e089f | |||
| cb4f6aaf82 | |||
| c978d87fef | |||
| 1c32aebff9 | |||
| 00a660d019 | |||
| 1102c08b3e | |||
| 3875486fbf | |||
| e6a8e54172 | |||
| e0f9a2f1e2 | |||
| e2b55c3b54 | |||
| be983825ab | |||
| faceab68f1 | |||
| aa796deeff | |||
| 2863dd0acc | |||
| 48fea32500 | |||
| b4b11329c2 | |||
| f118ada39e | |||
| 1a23f24b81 | |||
| edf898ae1a | |||
| bf29c09522 | |||
| d3b621f90b | |||
| 47620fe79e | |||
| 1bc275ea46 | |||
| d4f0161e14 | |||
| d59c8f1506 | |||
| 752a076236 | |||
| 8089e75ab2 | |||
| 3720c2adf7 | |||
| dbbff3d04f | |||
| b937c4bf38 | |||
| 54f5de4c2c | |||
| 39281188bc | |||
| 4678c53a48 | |||
| 6dac7f0689 | |||
| 3310e07c9b | |||
| 3674ba3786 | |||
| f81dc8cdac | |||
| f3ac3d9be4 | |||
| fcb865ea28 | |||
| 5bb3249dfe | |||
| eb12834ee3 | |||
| 214fec208d | |||
| ec948f980e | |||
| d63db655d8 | |||
| 2ab7339381 | |||
| c2ee0ebd42 | |||
| 654769af1e | |||
| 244419d686 | |||
| 6d6a5f4db0 | |||
| f722c6fdc8 | |||
| 9db23444db | |||
| 8e102446fe | |||
| e7e4406e77 | |||
| bec1108fa1 | |||
| 42f4d4e4a6 | |||
| a7c6a20dcc | |||
| 90bff11417 | |||
| 2c3e8fbdc0 | |||
| 690be9d80a | |||
| e584e3202b | |||
| 427249b5a9 | |||
| 6efbf3a3df | |||
| edf7d4f5c8 | |||
| 287d3cbe63 | |||
| 2bc9b410a6 | |||
| 6ecb271576 | |||
| 8b35f4d3b7 | |||
| 4a9eb76944 | |||
| e18ab1a880 | |||
| fa34aafabe | |||
| ffc08173b4 | |||
| 4fdcc0bf92 | |||
| 81dbb8483f | |||
| fa33977469 | |||
| 5bd7c64c97 | |||
| 095f7b5338 | |||
| 0b735eba40 | |||
| 0b7bd72231 | |||
| b1d1075dfe | |||
| 8b730dc543 | |||
| dc74901638 | |||
| 5115c587ff | |||
| 9286cfff66 | |||
| 2c66044550 | |||
| 2f22560f3d | |||
| 1eb9789780 | |||
| 0cf7b4be9b | |||
| b19d8f8745 | |||
| 864d815bc4 |
@@ -54,12 +54,18 @@ Powered Rail
|
||||
27 150 134 102 180 120 107 81 180 75 67 51 180 60 53 40 180
|
||||
Detector Rail
|
||||
28 150 134 102 180 120 107 81 180 75 67 51 180 60 53 40 180
|
||||
Sticky Piston
|
||||
29 157 128 79 255 96 96 96 255 78 64 39 255 48 48 48 255
|
||||
Cobweb
|
||||
30 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
|
||||
Tall Grass
|
||||
31 97 156 53 255 73 120 38 255 38 68 16 255 26 50 9 255
|
||||
Dead Shrubs
|
||||
32 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
|
||||
Piston
|
||||
33 157 128 79 255 96 96 96 255 78 64 39 255 48 48 48 255
|
||||
Piston Head
|
||||
34 157 128 79 255 96 96 96 255 78 64 39 255 48 48 48 255
|
||||
Wool
|
||||
35 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
|
||||
35:0 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
|
||||
@@ -227,3 +233,37 @@ Locked Chest
|
||||
95 125 91 38 255 100 72 30 255 62 45 19 255 50 36 15 255
|
||||
Trap Door
|
||||
96 111 91 54 255 88 72 43 255 55 45 27 255 44 36 21 255
|
||||
Biome Rainforest - Dark Green
|
||||
[RAINFOREST] 49 67 21 255 39 53 17 255 24 34 10 255 19 27 8 255
|
||||
Biome Swampland - Brown
|
||||
[SWAMPLAND] 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
|
||||
Biome Seasonal Forest - Light Green
|
||||
[SEASONAL_FOREST] 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
|
||||
Biome Forest - Light Gray
|
||||
[FOREST] 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
|
||||
Biome Savanna - Dark Gray
|
||||
[SAVANNA] 58 58 58 255 47 47 47 255 29 29 29 255 23 23 23 255
|
||||
Biome Shrubland - Yellow
|
||||
[SHRUBLAND] 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
|
||||
Biome Taiga - Cyan
|
||||
[TAIGA] 34 102 131 255 27 81 104 255 17 51 65 255 13 40 52 255
|
||||
Biome Desert - Orange
|
||||
[DESERT] 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
|
||||
Biome Plains - Magenta
|
||||
[PLAINS] 166 66 175 255 133 53 140 255 83 33 87 255 66 26 69 255
|
||||
Biome Ice Desert - Dark Blue
|
||||
[ICE_DESERT] 26 33 103 255 20 26 80 255 13 17 50 255 9 14 40 255
|
||||
Biome Tundra - White
|
||||
[TUNDRA] 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
|
||||
Biome Hell - Pink
|
||||
[HELL] 190 115 135 255 151 92 108 255 95 57 67 255 75 46 53 255
|
||||
Biome Sky - Blue
|
||||
[SKY] 34 44 134 255 27 35 107 255 17 22 67 255 13 18 53 255
|
||||
[RAINFALL-0.0] 120 120 120 255 96 96 96 255 60 60 60 255 48 48 48 255
|
||||
[RAINFALL-1.0] 38 92 255 255 30 73 204 255 19 46 127 255 15 36 102 255
|
||||
[TEMPERATURE-0.0] 38 92 255 255 30 73 204 255 19 46 127 255 15 36 102 255
|
||||
[TEMPERATURE-0.5] 91 121 185 255 73 96 147 255 46 61 92 255 36 48 73 255
|
||||
[TEMPERATURE-0.8] 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
|
||||
[TEMPERATURE-0.9] 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
|
||||
[TEMPERATURE-0.95] 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
|
||||
[TEMPERATURE-1.0] 143 39 36 255 114 31 28 255 71 20 18 255 57 16 14 255
|
||||
|
||||
@@ -54,12 +54,18 @@ Powered Rail
|
||||
27 150 134 102 180 120 107 81 180 75 67 51 180 60 53 40 180
|
||||
Detector Rail
|
||||
28 150 134 102 180 120 107 81 180 75 67 51 180 60 53 40 180
|
||||
Sticky Piston
|
||||
29 157 128 79 255 96 96 96 255 78 64 39 255 48 48 48 255
|
||||
Cobweb
|
||||
30 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
|
||||
Tall Grass
|
||||
31 97 156 53 255 73 120 38 255 38 68 16 255 26 50 9 255
|
||||
Dead Shrubs
|
||||
32 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
|
||||
Piston
|
||||
33 157 128 79 255 96 96 96 255 78 64 39 255 48 48 48 255
|
||||
Piston Head
|
||||
34 157 128 79 255 96 96 96 255 78 64 39 255 48 48 48 255
|
||||
Wool
|
||||
35 247 255 239 255 244 251 236 255 204 210 197 255 244 251 236 255
|
||||
35:0 247 255 239 255 244 251 236 255 204 210 197 255 244 251 236 255
|
||||
@@ -227,3 +233,37 @@ Locked Chest
|
||||
95 125 91 38 255 100 72 30 255 62 45 19 255 50 36 15 255
|
||||
Trap Door
|
||||
96 111 91 54 255 88 72 43 255 55 45 27 255 44 36 21 255
|
||||
Biome Rainforest - Dark Green
|
||||
[RAINFOREST] 49 67 21 255 39 53 17 255 24 34 10 255 19 27 8 255
|
||||
Biome Swampland - Brown
|
||||
[SWAMPLAND] 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
|
||||
Biome Seasonal Forest - Light Green
|
||||
[SEASONAL_FOREST] 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
|
||||
Biome Forest - Light Gray
|
||||
[FOREST] 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
|
||||
Biome Savanna - Dark Gray
|
||||
[SAVANNA] 58 58 58 255 47 47 47 255 29 29 29 255 23 23 23 255
|
||||
Biome Shrubland - Yellow
|
||||
[SHRUBLAND] 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
|
||||
Biome Taiga - Cyan
|
||||
[TAIGA] 34 102 131 255 27 81 104 255 17 51 65 255 13 40 52 255
|
||||
Biome Desert - Orange
|
||||
[DESERT] 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
|
||||
Biome Plains - Magenta
|
||||
[PLAINS] 166 66 175 255 133 53 140 255 83 33 87 255 66 26 69 255
|
||||
Biome Ice Desert - Dark Blue
|
||||
[ICE_DESERT] 26 33 103 255 20 26 80 255 13 17 50 255 9 14 40 255
|
||||
Biome Tundra - White
|
||||
[TUNDRA] 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
|
||||
Biome Hell - Pink
|
||||
[HELL] 190 115 135 255 151 92 108 255 95 57 67 255 75 46 53 255
|
||||
Biome Sky - Blue
|
||||
[SKY] 34 44 134 255 27 35 107 255 17 22 67 255 13 18 53 255
|
||||
[RAINFALL-0.0] 120 120 120 255 96 96 96 255 60 60 60 255 48 48 48 255
|
||||
[RAINFALL-1.0] 38 92 255 255 30 73 204 255 19 46 127 255 15 36 102 255
|
||||
[TEMPERATURE-0.0] 38 92 255 255 30 73 204 255 19 46 127 255 15 36 102 255
|
||||
[TEMPERATURE-0.5] 91 121 185 255 73 96 147 255 46 61 92 255 36 48 73 255
|
||||
[TEMPERATURE-0.8] 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
|
||||
[TEMPERATURE-0.9] 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
|
||||
[TEMPERATURE-0.95] 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
|
||||
[TEMPERATURE-1.0] 143 39 36 255 114 31 28 255 71 20 18 255 57 16 14 255
|
||||
|
||||
@@ -54,12 +54,18 @@ Powered Rail
|
||||
27 150 134 102 180 120 107 81 180 75 67 51 180 60 53 40 180
|
||||
Detector Rail
|
||||
28 150 134 102 180 120 107 81 180 75 67 51 180 60 53 40 180
|
||||
Sticky Piston
|
||||
29 157 128 79 255 125 122 116 255 78 64 39 255 88 85 81 255
|
||||
Cobweb
|
||||
30 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
|
||||
Tall Grass
|
||||
31 111 185 79 255 86 158 53 255 65 131 40 255 57 105 21 255
|
||||
Dead Shrubs
|
||||
32 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
|
||||
Piston
|
||||
33 157 128 79 255 125 122 116 255 78 64 39 255 88 85 81 255
|
||||
Piston Head
|
||||
34 157 128 79 255 125 122 116 255 78 64 39 255 88 85 81 255
|
||||
Wool
|
||||
35 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
|
||||
35:0 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
|
||||
@@ -227,4 +233,37 @@ Locked Chest
|
||||
95 125 91 38 255 100 72 30 255 62 45 19 255 50 36 15 255
|
||||
Trap Door
|
||||
96 111 91 54 255 88 72 43 255 55 45 27 255 44 36 21 255
|
||||
|
||||
Biome Rainforest - Dark Green
|
||||
[RAINFOREST] 49 67 21 255 39 53 17 255 24 34 10 255 19 27 8 255
|
||||
Biome Swampland - Brown
|
||||
[SWAMPLAND] 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
|
||||
Biome Seasonal Forest - Light Green
|
||||
[SEASONAL_FOREST] 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
|
||||
Biome Forest - Light Gray
|
||||
[FOREST] 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
|
||||
Biome Savanna - Dark Gray
|
||||
[SAVANNA] 58 58 58 255 47 47 47 255 29 29 29 255 23 23 23 255
|
||||
Biome Shrubland - Yellow
|
||||
[SHRUBLAND] 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
|
||||
Biome Taiga - Cyan
|
||||
[TAIGA] 34 102 131 255 27 81 104 255 17 51 65 255 13 40 52 255
|
||||
Biome Desert - Orange
|
||||
[DESERT] 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
|
||||
Biome Plains - Magenta
|
||||
[PLAINS] 166 66 175 255 133 53 140 255 83 33 87 255 66 26 69 255
|
||||
Biome Ice Desert - Dark Blue
|
||||
[ICE_DESERT] 26 33 103 255 20 26 80 255 13 17 50 255 9 14 40 255
|
||||
Biome Tundra - White
|
||||
[TUNDRA] 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
|
||||
Biome Hell - Pink
|
||||
[HELL] 190 115 135 255 151 92 108 255 95 57 67 255 75 46 53 255
|
||||
Biome Sky - Blue
|
||||
[SKY] 34 44 134 255 27 35 107 255 17 22 67 255 13 18 53 255
|
||||
[RAINFALL-0.0] 120 120 120 255 96 96 96 255 60 60 60 255 48 48 48 255
|
||||
[RAINFALL-1.0] 38 92 255 255 30 73 204 255 19 46 127 255 15 36 102 255
|
||||
[TEMPERATURE-0.0] 38 92 255 255 30 73 204 255 19 46 127 255 15 36 102 255
|
||||
[TEMPERATURE-0.5] 91 121 185 255 73 96 147 255 46 61 92 255 36 48 73 255
|
||||
[TEMPERATURE-0.8] 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
|
||||
[TEMPERATURE-0.9] 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
|
||||
[TEMPERATURE-0.95] 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
|
||||
[TEMPERATURE-1.0] 143 39 36 255 114 31 28 255 71 20 18 255 57 16 14 255
|
||||
|
||||
+38
-1
@@ -25,9 +25,12 @@
|
||||
26 200 20 20 255 160 16 16 255 100 10 10 255 80 8 8 255
|
||||
27 150 134 102 180 120 107 81 180 75 67 51 180 60 53 40 180
|
||||
28 150 134 102 180 120 107 81 180 75 67 51 180 60 53 40 180
|
||||
29 109 80 60 255 111 108 98 255 76 56 41 255 111 108 98 255
|
||||
30 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
|
||||
31 97 156 53 255 73 120 38 255 38 68 16 255 26 50 9 255
|
||||
32 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
|
||||
33 109 80 60 255 111 108 98 255 76 56 41 255 111 108 98 255
|
||||
34 109 80 60 255 111 108 98 255 76 56 41 255 111 108 98 255
|
||||
35 247 255 239 255 244 251 236 255 204 210 197 255 244 251 236 255
|
||||
35:0 247 255 239 255 244 251 236 255 204 210 197 255 244 251 236 255
|
||||
35:1 227 128 52 255 224 126 51 255 187 105 42 255 224 126 51 255
|
||||
@@ -112,4 +115,38 @@
|
||||
93 159 127 80 255 72 56 25 0 181 140 64 255 144 112 51 0
|
||||
94 159 127 80 255 102 0 0 0 255 0 0 255 204 0 0 0
|
||||
95 125 91 38 255 100 72 30 255 62 45 19 255 50 36 15 255
|
||||
96 111 91 54 255 88 72 43 255 55 45 27 255 44 36 21 255
|
||||
96 111 91 54 255 88 72 43 255 55 45 27 255 44 36 21 255
|
||||
Biome Rainforest - Dark Green
|
||||
[RAINFOREST] 49 67 21 255 39 53 17 255 24 34 10 255 19 27 8 255
|
||||
Biome Swampland - Brown
|
||||
[SWAMPLAND] 75 44 24 255 60 35 19 255 37 22 12 255 30 18 10 255
|
||||
Biome Seasonal Forest - Light Green
|
||||
[SEASONAL_FOREST] 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
|
||||
Biome Forest - Light Gray
|
||||
[FOREST] 138 145 145 255 110 115 115 255 69 72 72 255 55 57 57 255
|
||||
Biome Savanna - Dark Gray
|
||||
[SAVANNA] 58 58 58 255 47 47 47 255 29 29 29 255 23 23 23 255
|
||||
Biome Shrubland - Yellow
|
||||
[SHRUBLAND] 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
|
||||
Biome Taiga - Cyan
|
||||
[TAIGA] 34 102 131 255 27 81 104 255 17 51 65 255 13 40 52 255
|
||||
Biome Desert - Orange
|
||||
[DESERT] 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
|
||||
Biome Plains - Magenta
|
||||
[PLAINS] 166 66 175 255 133 53 140 255 83 33 87 255 66 26 69 255
|
||||
Biome Ice Desert - Dark Blue
|
||||
[ICE_DESERT] 26 33 103 255 20 26 80 255 13 17 50 255 9 14 40 255
|
||||
Biome Tundra - White
|
||||
[TUNDRA] 222 222 222 255 177 177 177 255 111 111 111 255 88 88 88 255
|
||||
Biome Hell - Pink
|
||||
[HELL] 190 115 135 255 151 92 108 255 95 57 67 255 75 46 53 255
|
||||
Biome Sky - Blue
|
||||
[SKY] 34 44 134 255 27 35 107 255 17 22 67 255 13 18 53 255
|
||||
[RAINFALL-0.0] 120 120 120 255 96 96 96 255 60 60 60 255 48 48 48 255
|
||||
[RAINFALL-1.0] 38 92 255 255 30 73 204 255 19 46 127 255 15 36 102 255
|
||||
[TEMPERATURE-0.0] 38 92 255 255 30 73 204 255 19 46 127 255 15 36 102 255
|
||||
[TEMPERATURE-0.5] 91 121 185 255 73 96 147 255 46 61 92 255 36 48 73 255
|
||||
[TEMPERATURE-0.8] 51 165 42 255 41 131 33 255 26 82 21 255 20 65 17 255
|
||||
[TEMPERATURE-0.9] 170 158 24 255 135 126 19 255 85 79 12 255 67 62 10 255
|
||||
[TEMPERATURE-0.95] 204 111 48 255 162 89 38 255 102 56 24 255 81 44 19 255
|
||||
[TEMPERATURE-1.0] 143 39 36 255 114 31 28 255 71 20 18 255 57 16 14 255
|
||||
|
||||
+138
-63
@@ -9,6 +9,7 @@ components:
|
||||
allowwebchat: true
|
||||
webchat-interval: 5
|
||||
hidewebchatip: false
|
||||
trustclientname: false
|
||||
#- class: org.dynmap.JsonFileClientUpdateComponent
|
||||
# writeinterval: 1
|
||||
# sendhealth: true
|
||||
@@ -60,6 +61,10 @@ components:
|
||||
# strokeWeight: 3
|
||||
# fillColor: "#FF0000"
|
||||
# fillOpacity: 0.35
|
||||
# # Optional setting to limit which regions to show, by name - if commented out, all regions are shown
|
||||
# visibleregions:
|
||||
# - homebase
|
||||
# - miningsite
|
||||
#- class: org.dynmap.TestComponent
|
||||
# stuff: "This is some configuration-value"
|
||||
|
||||
@@ -69,15 +74,22 @@ display-whitelist: false
|
||||
# How often a tile gets rendered (in seconds).
|
||||
renderinterval: 1
|
||||
|
||||
# Zoom-out tile update period - how often to scan for and process tile updates into zoom-out tiles (in seconds)
|
||||
zoomoutperiod: 60
|
||||
|
||||
# Tile hashing is used to minimize tile file updates when no changes have occurred - set to false to disable
|
||||
enabletilehash: true
|
||||
|
||||
render-triggers:
|
||||
# - chunkloaded
|
||||
# - playermove
|
||||
# - playerjoin
|
||||
#- chunkloaded
|
||||
#- playermove
|
||||
#- playerjoin
|
||||
- blockplaced
|
||||
- blockbreak
|
||||
- snowform
|
||||
- leavesdecay
|
||||
- blockburn
|
||||
- chunkgenerated
|
||||
|
||||
# The path where the tile-files are placed.
|
||||
tilespath: web/tiles
|
||||
@@ -94,9 +106,15 @@ webserver-port: 8123
|
||||
# Disables Webserver portion of Dynmap (Advanced users only)
|
||||
disable-webserver: false
|
||||
|
||||
# Enable/disable having the web server allow symbolic links (true=compatible with existing code, false=more secure (default))
|
||||
allow-symlinks: true
|
||||
|
||||
# Period between tile renders for fullrender, in seconds (non-zero to pace fullrenders, lessen CPU load)
|
||||
timesliceinterval: 0.0
|
||||
|
||||
# Maximum chunk loads per server tick (1/20th of a second) - reducing this below 90 will impact render performance, but also will reduce server thread load
|
||||
maxchunkspertick: 200
|
||||
|
||||
# Interval the browser should poll for updates.
|
||||
updaterate: 2000
|
||||
|
||||
@@ -121,6 +139,10 @@ templates:
|
||||
# Template for normal world
|
||||
normal:
|
||||
enabled: true
|
||||
# # If bigworld set to true, use alternate directory layout better suited to large worlds
|
||||
# bigworld: true
|
||||
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
|
||||
# extrazoomout: 3
|
||||
center:
|
||||
x: 0
|
||||
y: 64
|
||||
@@ -131,19 +153,21 @@ templates:
|
||||
title: "Flat"
|
||||
prefix: flat
|
||||
colorscheme: default
|
||||
# To render a world as a "night view", set shadowstrength and ambientlight
|
||||
# shadowstrength: 1.0
|
||||
# ambientlight: 4
|
||||
# To render both night and day versions of tiles (when ambientlight is set), set true
|
||||
# night-and-day: true
|
||||
# Option to turn on transparency support (off by default) - slows render
|
||||
# transparency: true
|
||||
# Background color for map during the day
|
||||
# backgroundday: "#153E7E"
|
||||
# Background color for map during the night
|
||||
# backgroundnight: "#000000"
|
||||
# Backgrounc color for map (independent of night/day)
|
||||
# background: "#000000"
|
||||
# The textured setting makes the flat render toning much more consistent with the other maps: set to 'none' for the original flat texture, 'smooth' for blended tile top colors, 'dither' for dither pattern
|
||||
textured: smooth
|
||||
# # To render a world as a "night view", set shadowstrength and ambientlight
|
||||
# shadowstrength: 1.0
|
||||
# ambientlight: 4
|
||||
# # To render both night and day versions of tiles (when ambientlight is set), set true
|
||||
# night-and-day: true
|
||||
# # Option to turn on transparency support (off by default) - slows render
|
||||
# transparency: true
|
||||
# # Background color for map during the day
|
||||
# backgroundday: "#153E7E"
|
||||
# # Background color for map during the night
|
||||
# backgroundnight: "#000000"
|
||||
# # Background color for map (independent of night/day)
|
||||
# background: "#000000"
|
||||
- class: org.dynmap.kzedmap.KzedMap
|
||||
renderers:
|
||||
- class: org.dynmap.kzedmap.DefaultTileRenderer
|
||||
@@ -152,30 +176,39 @@ templates:
|
||||
prefix: t
|
||||
maximumheight: 127
|
||||
colorscheme: default
|
||||
# Add shadows to world (based on top-down shadows from chunk data)
|
||||
# shadowstrength: 1.0
|
||||
# To render a world as a "night view", set shadowstrength and ambientlight
|
||||
# ambientlight: 4
|
||||
# To render both night and day versions of tiles (when ambientlight is set), set true
|
||||
# night-and-day: true
|
||||
# Option to turn off transparency support (on by default) - speeds render
|
||||
# transparency: false
|
||||
# Background color for map during the day
|
||||
# backgroundday: "#153E7E"
|
||||
# Background color for map during the night
|
||||
# backgroundnight: "#000000"
|
||||
# Backgrounc color for map (independent of night/day)
|
||||
# background: "#000000"
|
||||
# Sets the icon to 'images/block_custom.png'
|
||||
# icon: custom
|
||||
#- class: org.dynmap.kzedmap.HighlightTileRenderer
|
||||
# prefix: ht
|
||||
# maximumheight: 127
|
||||
# colorscheme: default
|
||||
# highlight: # For highlighting multiple block-types.
|
||||
# - 56 # Highlight diamond-ore
|
||||
# - 66 # Highlight minecart track
|
||||
# highlight: 56 # For highlighting a single block-type.
|
||||
# # Add shadows to world (based on top-down shadows from chunk data)
|
||||
# shadowstrength: 1.0
|
||||
# # To render a world as a "night view", set shadowstrength and ambientlight
|
||||
# ambientlight: 4
|
||||
# # To render both night and day versions of tiles (when ambientlight is set), set true
|
||||
# night-and-day: true
|
||||
# # Option to turn off transparency support (on by default) - speeds render
|
||||
# transparency: false
|
||||
# # Background color for map during the day
|
||||
# backgroundday: "#153E7E"
|
||||
# # Background color for map during the night
|
||||
# backgroundnight: "#000000"
|
||||
# # Background color for map (independent of night/day)
|
||||
# background: "#000000"
|
||||
# # Sets the icon to 'images/block_custom.png'
|
||||
# icon: custom
|
||||
# # Biome-based mapping
|
||||
# - class: org.dynmap.kzedmap.DefaultTileRenderer
|
||||
# name: biome
|
||||
# title: "Biome"
|
||||
# prefix: b
|
||||
# maximumheight: 127
|
||||
# colorscheme: default
|
||||
# # Biome-based coloring : biome=biome type, temperature=biome-temperature, rainfall=biome-rainfall
|
||||
# biomecolored: biome
|
||||
# - class: org.dynmap.kzedmap.HighlightTileRenderer
|
||||
# prefix: ht
|
||||
# maximumheight: 127
|
||||
# colorscheme: default
|
||||
# highlight: # For highlighting multiple block-types.
|
||||
# - 56 # Highlight diamond-ore
|
||||
# - 66 # Highlight minecart track
|
||||
# highlight: 56 # For highlighting a single block-type.
|
||||
- class: org.dynmap.kzedmap.CaveTileRenderer
|
||||
name: cave
|
||||
title: "Cave"
|
||||
@@ -184,6 +217,10 @@ templates:
|
||||
# Nether world template
|
||||
nether:
|
||||
enabled: true
|
||||
# # If bigworld set to true, use alternate directory layout better suited to large worlds
|
||||
# bigworld: true
|
||||
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
|
||||
# extrazoomout: 3
|
||||
center:
|
||||
x: 0
|
||||
y: 64
|
||||
@@ -196,6 +233,8 @@ templates:
|
||||
colorscheme: default
|
||||
# Map background color (day or night)
|
||||
background: "#300806"
|
||||
# The textured setting makes the flat render toning much more consistent with the other maps: set to 'none' for the original flat texture, 'smooth' for blended tile top colors, 'dither' for dither pattern
|
||||
textured: smooth
|
||||
- class: org.dynmap.kzedmap.KzedMap
|
||||
renderers:
|
||||
- class: org.dynmap.kzedmap.DefaultTileRenderer
|
||||
@@ -209,6 +248,10 @@ templates:
|
||||
# Skylands world template
|
||||
skylands:
|
||||
enabled: true
|
||||
# # If bigworld set to true, use alternate directory layout better suited to large worlds
|
||||
# bigworld: true
|
||||
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
|
||||
# extrazoomout: 3
|
||||
center:
|
||||
x: 0
|
||||
y: 64
|
||||
@@ -223,6 +266,8 @@ templates:
|
||||
backgroundday: "#153E7E"
|
||||
# Background color for map during the night
|
||||
backgroundnight: "#000000"
|
||||
# The textured setting makes the flat render toning much more consistent with the other maps: set to 'none' for the original flat texture, 'smooth' for blended tile top colors, 'dither' for dither pattern
|
||||
textured: smooth
|
||||
- class: org.dynmap.kzedmap.KzedMap
|
||||
renderers:
|
||||
- class: org.dynmap.kzedmap.DefaultTileRenderer
|
||||
@@ -260,6 +305,22 @@ worlds:
|
||||
# - x: -15000
|
||||
# y: 64
|
||||
# z: -5000
|
||||
# # Use visibilitylimits to restrict which areas of maps on your world to render (zero or more rectangles can be defined)
|
||||
# visibilitylimits:
|
||||
# - x0: -1000
|
||||
# z0: -1000
|
||||
# x1: 1000
|
||||
# z1: 1000
|
||||
# - x0: -2000
|
||||
# z0: -1000
|
||||
# x1: -1000
|
||||
# z1: -500
|
||||
# # Use hidestyle to control how hidden-but-existing chunks are to be rendered (air=empty air (same as ungenerated), stone=a flat stone plain, ocean=a flat ocean)
|
||||
# hidestyle: stone
|
||||
# # Use 'autogenerate-to-visibilitylimits: true' to choose to force the generation of ungenerated chunks while rendering maps on this world, for any chunks within the defined
|
||||
# # visibilitylimits (limits must be set). The three options here are: none (default - no autogenerate), map-only (temporarily generate chunks for map, but don't save them (no world change),
|
||||
# # permanent (generate and save chunks - this permanently adds the chunks to the world, as if a player had visited them - BE SURE THIS IS WHAT YOU WANT)
|
||||
# autogenerate-to-visibilitylimits: map-only
|
||||
# Use 'template: mycustomtemplate' to use the properties specified in the template 'mycustomtemplate' to this world. Default it is set to the environment-name (normal or nether).
|
||||
# template: mycustomtemplate
|
||||
# Rest of comes from template - uncomment to tailor for world specifically
|
||||
@@ -267,25 +328,31 @@ worlds:
|
||||
# x: 0
|
||||
# y: 64
|
||||
# z: 0
|
||||
# # If bigworld set to true, use alternate directory layout better suited to large worlds
|
||||
# bigworld: true
|
||||
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
|
||||
# extrazoomout: 3
|
||||
# maps:
|
||||
# - class: org.dynmap.flat.FlatMap
|
||||
# name: flat
|
||||
# title: "Flat"
|
||||
# prefix: flat
|
||||
# colorscheme: default
|
||||
# # The textured setting makes the flat render toning much more consistent with the other maps: set to 'none' for the original flat texture, 'smooth' for blended tile top colors, 'dither' for dither pattern
|
||||
# textured: smooth
|
||||
# # To render a world as a "night view", set shadowstrength and ambientlight
|
||||
# # shadowstrength: 1.0
|
||||
# # ambientlight: 4
|
||||
# shadowstrength: 1.0
|
||||
# ambientlight: 4
|
||||
# # To render both night and day versions of tiles (when ambientlight is set), set true
|
||||
# # night-and-day: true
|
||||
# night-and-day: true
|
||||
# # Option to turn on transparency support (off by default) - slows render
|
||||
# # transparency: true
|
||||
# transparency: true
|
||||
# # Background color for map during the day
|
||||
# # backgroundday: "#153E7E"
|
||||
# backgroundday: "#153E7E"
|
||||
# # Background color for map during the night
|
||||
# # backgroundnight: "#000000"
|
||||
# backgroundnight: "#000000"
|
||||
# # Backgrounc color for map (independent of night/day)
|
||||
# # background: "#000000"
|
||||
# background: "#000000"
|
||||
# - class: org.dynmap.kzedmap.KzedMap
|
||||
# renderers:
|
||||
# - class: org.dynmap.kzedmap.DefaultTileRenderer
|
||||
@@ -295,29 +362,29 @@ worlds:
|
||||
# maximumheight: 127
|
||||
# colorscheme: default
|
||||
# # Add shadows to world (based on top-down shadows from chunk data)
|
||||
# # shadowstrength: 1.0
|
||||
# shadowstrength: 1.0
|
||||
# # To render a world as a "night view", set shadowstrength and ambientlight
|
||||
# # ambientlight: 4
|
||||
# ambientlight: 4
|
||||
# # To render both night and day versions of tiles (when ambientlight is set), set true
|
||||
# # night-and-day: true
|
||||
# night-and-day: true
|
||||
# # Option to turn off transparency support (on by default) - speeds render
|
||||
# # transparency: false
|
||||
# transparency: false
|
||||
# # Background color for map during the day
|
||||
# # backgroundday: "#153E7E"
|
||||
# backgroundday: "#153E7E"
|
||||
# # Background color for map during the night
|
||||
# # backgroundnight: "#000000"
|
||||
# backgroundnight: "#000000"
|
||||
# # Backgrounc color for map (independent of night/day)
|
||||
# # background: "#000000"
|
||||
# background: "#000000"
|
||||
# # Sets the icon to 'images/block_custom.png'
|
||||
# # icon: custom
|
||||
# #- class: org.dynmap.kzedmap.HighlightTileRenderer
|
||||
# # prefix: ht
|
||||
# # maximumheight: 127
|
||||
# # colorscheme: default
|
||||
# # highlight: # For highlighting multiple block-types.
|
||||
# # - 56 # Highlight diamond-ore
|
||||
# # - 66 # Highlight minecart track
|
||||
# # highlight: 56 # For highlighting a single block-type.
|
||||
# icon: custom
|
||||
# - class: org.dynmap.kzedmap.HighlightTileRenderer
|
||||
# prefix: ht
|
||||
# maximumheight: 127
|
||||
# colorscheme: default
|
||||
# highlight: # For highlighting multiple block-types.
|
||||
# - 56 # Highlight diamond-ore
|
||||
# - 66 # Highlight minecart track
|
||||
# highlight: 56 # For highlighting a single block-type.
|
||||
# - class: org.dynmap.kzedmap.CaveTileRenderer
|
||||
# name: cave
|
||||
# title: "Cave"
|
||||
@@ -334,12 +401,16 @@ worlds:
|
||||
# x: 0
|
||||
# y: 64
|
||||
# z: 0
|
||||
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
|
||||
# extrazoomout: 3
|
||||
# maps:
|
||||
# - class: org.dynmap.flat.FlatMap
|
||||
# name: flat
|
||||
# title: "Flat"
|
||||
# prefix: flat
|
||||
# colorscheme: default
|
||||
# # The textured setting makes the flat render toning much more consistent with the other maps: set to 'none' for the original flat texture, 'smooth' for blended tile top colors, 'dither' for dither pattern
|
||||
# textured: smooth
|
||||
# - class: org.dynmap.kzedmap.KzedMap
|
||||
# renderers:
|
||||
# - class: org.dynmap.kzedmap.DefaultTileRenderer
|
||||
@@ -349,6 +420,10 @@ worlds:
|
||||
# maximumheight: 127
|
||||
# colorscheme: default
|
||||
|
||||
# Set to true to enable verbose startup messages - can help with debugging map configuration problems
|
||||
# Set to false for a much quieter startup log
|
||||
verbose: true
|
||||
|
||||
# Enables debugging.
|
||||
#debuggers:
|
||||
# - class: org.dynmap.debug.LogDebugger
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.dynmap</groupId>
|
||||
<artifactId>dynmap</artifactId>
|
||||
<version>0.18</version>
|
||||
<version>0.19.2</version>
|
||||
<name>dynmap</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.dynmap;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.Material;
|
||||
|
||||
public class Armor {
|
||||
/**
|
||||
@@ -17,7 +18,12 @@ public class Armor {
|
||||
double baseArmorPoints = 0;
|
||||
ItemStack inventory[] = player.getInventory().getArmorContents();
|
||||
for(int i=0;i<inventory.length;i++) {
|
||||
final short maxDurability = inventory[i].getType().getMaxDurability();
|
||||
if(inventory[i] == null)
|
||||
continue;
|
||||
Material m = inventory[i].getType();
|
||||
if(m == null)
|
||||
continue;
|
||||
final short maxDurability = m.getMaxDurability();
|
||||
if(maxDurability < 0)
|
||||
continue;
|
||||
final short durability = inventory[i].getDurability();
|
||||
|
||||
@@ -39,6 +39,7 @@ public class ClientComponent extends Component {
|
||||
return o;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static final JSONArray convertList(List<?> l) {
|
||||
JSONArray o = new JSONArray();
|
||||
for(Object entry : l) {
|
||||
@@ -47,6 +48,7 @@ public class ClientComponent extends Component {
|
||||
return o;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static final Object convert(Object o) {
|
||||
if (o instanceof Map<?, ?>) {
|
||||
return convertMap((Map<String, ?>)o);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.dynmap;
|
||||
|
||||
import static org.dynmap.JSONUtils.a;
|
||||
import static org.dynmap.JSONUtils.l;
|
||||
import static org.dynmap.JSONUtils.s;
|
||||
|
||||
import org.dynmap.Event.Listener;
|
||||
@@ -33,6 +32,8 @@ public class ClientConfigurationComponent extends Component {
|
||||
s(wo, "center/x", wn.getFloat("center/x", 0.0f));
|
||||
s(wo, "center/y", wn.getFloat("center/y", 64.0f));
|
||||
s(wo, "center/z", wn.getFloat("center/z", 0.0f));
|
||||
s(wo, "bigworld", world.bigworld);
|
||||
s(wo, "extrazoomout", world.getExtraZoomOutLevels());
|
||||
a(t, "worlds", wo);
|
||||
|
||||
for(MapType mt : world.maps) {
|
||||
|
||||
@@ -8,19 +8,26 @@ import java.util.HashMap;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.dynmap.debug.Debug;
|
||||
import org.bukkit.block.Biome;
|
||||
|
||||
public class ColorScheme {
|
||||
private static final HashMap<String, ColorScheme> cache = new HashMap<String, ColorScheme>();
|
||||
|
||||
public String name;
|
||||
/* Switch to arrays - faster than map */
|
||||
public Color[][] colors; /* [blk-type][step] */
|
||||
public Color[][][] datacolors; /* [bkt-type][blk-dat][step] */
|
||||
public final Color[][] colors; /* [blk-type][step] */
|
||||
public final Color[][][] datacolors; /* [bkt-type][blk-dat][step] */
|
||||
public final Color[][] biomecolors; /* [Biome.ordinal][step] */
|
||||
public final Color[][] raincolors; /* [rain * 63][step] */
|
||||
public final Color[][] tempcolors; /* [temp * 63][step] */
|
||||
|
||||
public ColorScheme(String name, Color[][] colors, Color[][][] datacolors) {
|
||||
public ColorScheme(String name, Color[][] colors, Color[][][] datacolors, Color[][] biomecolors, Color[][] raincolors, Color[][] tempcolors) {
|
||||
this.name = name;
|
||||
this.colors = colors;
|
||||
this.datacolors = datacolors;
|
||||
this.biomecolors = biomecolors;
|
||||
this.raincolors = raincolors;
|
||||
this.tempcolors = tempcolors;
|
||||
}
|
||||
|
||||
private static File getColorSchemeDirectory() {
|
||||
@@ -42,6 +49,10 @@ public class ColorScheme {
|
||||
File colorSchemeFile = new File(getColorSchemeDirectory(), name + ".txt");
|
||||
Color[][] colors = new Color[256][];
|
||||
Color[][][] datacolors = new Color[256][][];
|
||||
Color[][] biomecolors = new Color[Biome.values().length][];
|
||||
Color[][] raincolors = new Color[64][];
|
||||
Color[][] tempcolors = new Color[64][];
|
||||
|
||||
InputStream stream;
|
||||
try {
|
||||
Debug.debug("Loading colors from '" + colorSchemeFile + "'...");
|
||||
@@ -54,30 +65,86 @@ public class ColorScheme {
|
||||
if (line.startsWith("#") || line.equals("")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String[] split = line.split("\t");
|
||||
/* Make parser less pedantic - tabs or spaces should be fine */
|
||||
String[] split = line.split("[\t ]");
|
||||
int cnt = 0;
|
||||
for(String s: split) { if(s.length() > 0) cnt++; }
|
||||
String[] nsplit = new String[cnt];
|
||||
cnt = 0;
|
||||
for(String s: split) { if(s.length() > 0) { nsplit[cnt] = s; cnt++; } }
|
||||
split = nsplit;
|
||||
if (split.length < 17) {
|
||||
continue;
|
||||
}
|
||||
Integer id;
|
||||
Integer dat = null;
|
||||
boolean isbiome = false;
|
||||
boolean istemp = false;
|
||||
boolean israin = false;
|
||||
int idx = split[0].indexOf(':');
|
||||
if(idx > 0) { /* ID:data - data color */
|
||||
id = new Integer(split[0].substring(0, idx));
|
||||
dat = new Integer(split[0].substring(idx+1));
|
||||
}
|
||||
else if(split[0].charAt(0) == '[') { /* Biome color data */
|
||||
String bio = split[0].substring(1);
|
||||
idx = bio.indexOf(']');
|
||||
if(idx >= 0) bio = bio.substring(0, idx);
|
||||
isbiome = true;
|
||||
id = -1;
|
||||
for(Biome b : Biome.values()) {
|
||||
if(b.toString().equalsIgnoreCase(bio)) {
|
||||
id = b.ordinal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(id < 0) { /* Not biome - check for rain or temp */
|
||||
if(bio.startsWith("RAINFALL-")) {
|
||||
try {
|
||||
double v = Double.parseDouble(bio.substring(9));
|
||||
if((v >= 0) && (v <= 1.00)) {
|
||||
id = (int)(v * 63.0);
|
||||
israin = true;
|
||||
}
|
||||
} catch (NumberFormatException nfx) {
|
||||
}
|
||||
}
|
||||
else if(bio.startsWith("TEMPERATURE-")) {
|
||||
try {
|
||||
double v = Double.parseDouble(bio.substring(12));
|
||||
if((v >= 0) && (v <= 1.00)) {
|
||||
id = (int)(v * 63.0);
|
||||
istemp = true;
|
||||
}
|
||||
} catch (NumberFormatException nfx) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
id = new Integer(split[0]);
|
||||
}
|
||||
Color[] c = new Color[4];
|
||||
Color[] c = new Color[5];
|
||||
|
||||
/* store colors by raycast sequence number */
|
||||
c[0] = new Color(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4]));
|
||||
c[3] = new Color(Integer.parseInt(split[5]), Integer.parseInt(split[6]), Integer.parseInt(split[7]), Integer.parseInt(split[8]));
|
||||
c[1] = new Color(Integer.parseInt(split[9]), Integer.parseInt(split[10]), Integer.parseInt(split[11]), Integer.parseInt(split[12]));
|
||||
c[2] = new Color(Integer.parseInt(split[13]), Integer.parseInt(split[14]), Integer.parseInt(split[15]), Integer.parseInt(split[16]));
|
||||
/* Blended color - for 'smooth' option on flat map */
|
||||
c[4] = new Color((c[0].getRed()+c[2].getRed())/2, (c[0].getGreen()+c[2].getGreen())/2, (c[0].getBlue()+c[2].getBlue())/2, (c[0].getAlpha()+c[2].getAlpha())/2);
|
||||
|
||||
if(dat != null) {
|
||||
if(isbiome) {
|
||||
if(istemp) {
|
||||
tempcolors[id] = c;
|
||||
}
|
||||
else if(israin) {
|
||||
raincolors[id] = c;
|
||||
}
|
||||
else if((id >= 0) && (id < biomecolors.length))
|
||||
biomecolors[id] = c;
|
||||
}
|
||||
else if(dat != null) {
|
||||
Color[][] dcolor = datacolors[id]; /* Existing list? */
|
||||
if(dcolor == null) {
|
||||
dcolor = new Color[16][]; /* Make 16 index long list */
|
||||
@@ -107,12 +174,65 @@ public class ColorScheme {
|
||||
}
|
||||
}
|
||||
}
|
||||
/* And interpolate any missing rain and temperature colors */
|
||||
interpolateColorTable(tempcolors);
|
||||
interpolateColorTable(raincolors);
|
||||
} catch (RuntimeException e) {
|
||||
Log.severe("Could not load colors '" + name + "' ('" + colorSchemeFile + "').", e);
|
||||
return null;
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.severe("Could not load colors '" + name + "' ('" + colorSchemeFile + "'): File not found.", e);
|
||||
}
|
||||
return new ColorScheme(name, colors, datacolors);
|
||||
return new ColorScheme(name, colors, datacolors, biomecolors, raincolors, tempcolors);
|
||||
}
|
||||
|
||||
public static void interpolateColorTable(Color[][] c) {
|
||||
int idx = -1;
|
||||
for(int k = 0; k < c.length; k++) {
|
||||
if(c[k] == null) { /* Missing? */
|
||||
if((idx >= 0) && (k == (c.length-1))) { /* We're last - so fill forward from last color */
|
||||
for(int kk = idx+1; kk <= k; kk++) {
|
||||
c[kk] = c[idx];
|
||||
}
|
||||
}
|
||||
/* Skip - will backfill when we find next color */
|
||||
}
|
||||
else if(idx == -1) { /* No previous color, just backfill this color */
|
||||
for(int kk = 0; kk < k; kk++) {
|
||||
c[kk] = c[k];
|
||||
}
|
||||
idx = k; /* This is now last defined color */
|
||||
}
|
||||
else { /* Else, interpolate between last idx and this one */
|
||||
int cnt = c[k].length;
|
||||
for(int kk = idx+1; kk < k; kk++) {
|
||||
double interp = (double)(kk-idx)/(double)(k-idx);
|
||||
Color[] cc = new Color[cnt];
|
||||
for(int jj = 0; jj < cnt; jj++) {
|
||||
cc[jj] = new Color(
|
||||
(int)((1.0-interp)*c[idx][jj].getRed() + interp*c[k][jj].getRed()),
|
||||
(int)((1.0-interp)*c[idx][jj].getGreen() + interp*c[k][jj].getGreen()),
|
||||
(int)((1.0-interp)*c[idx][jj].getBlue() + interp*c[k][jj].getBlue()),
|
||||
(int)((1.0-interp)*c[idx][jj].getAlpha() + interp*c[k][jj].getAlpha()));
|
||||
}
|
||||
c[kk] = cc;
|
||||
}
|
||||
idx = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
public Color[] getRainColor(double rain) {
|
||||
int idx = (int)(rain * 63.0);
|
||||
if((idx >= 0) && (idx < raincolors.length))
|
||||
return raincolors[idx];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
public Color[] getTempColor(double temp) {
|
||||
int idx = (int)(temp * 63.0);
|
||||
if((idx >= 0) && (idx < tempcolors.length))
|
||||
return tempcolors[idx];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public class ConfigurationNode implements Map<String, Object> {
|
||||
entries = map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getObject(String path) {
|
||||
if (path.isEmpty())
|
||||
return entries;
|
||||
@@ -60,6 +61,7 @@ public class ConfigurationNode implements Map<String, Object> {
|
||||
return o;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getGeneric(String path, T def) {
|
||||
Object o = getObject(path, def);
|
||||
try {
|
||||
@@ -112,6 +114,7 @@ public class ConfigurationNode implements Map<String, Object> {
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> List<T> getList(String path) {
|
||||
try {
|
||||
List<T> list = (List<T>)getObject(path, null);
|
||||
@@ -139,6 +142,7 @@ public class ConfigurationNode implements Map<String, Object> {
|
||||
return new ConfigurationNode(v);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<ConfigurationNode> getNodes(String path) {
|
||||
List<Object> o = getList(path);
|
||||
|
||||
@@ -165,6 +169,7 @@ public class ConfigurationNode implements Map<String, Object> {
|
||||
extendMap(this, other);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final static void extendMap(Map<String, Object> left, Map<String, Object> right) {
|
||||
ConfigurationNode original = new ConfigurationNode(left);
|
||||
for(Map.Entry<String, Object> entry : right.entrySet()) {
|
||||
|
||||
@@ -18,8 +18,11 @@ import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockBurnEvent;
|
||||
import org.bukkit.event.block.BlockListener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.block.LeavesDecayEvent;
|
||||
import org.bukkit.event.block.SnowFormEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerListener;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
@@ -49,6 +52,8 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
public Events events = new Events();
|
||||
/* Flag to let code know that we're doing reload - make sure we don't double-register event handlers */
|
||||
public boolean is_reload = false;
|
||||
private boolean generate_only = false;
|
||||
private static boolean ignore_chunk_loads = false; /* Flat to keep us from processing our own chunk loads */
|
||||
|
||||
public static File dataDirectory;
|
||||
public static File tilesDirectory;
|
||||
@@ -73,6 +78,8 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
bukkitConfiguration.load();
|
||||
configuration = new ConfigurationNode(bukkitConfiguration);
|
||||
|
||||
Log.verbose = configuration.getBoolean("verbose", true);
|
||||
|
||||
loadDebuggers();
|
||||
|
||||
tilesDirectory = getFile(configuration.getString("tilespath", "web/tiles"));
|
||||
@@ -101,7 +108,7 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
for(Component component : configuration.<Component>createInstances("components", new Class<?>[] { DynmapPlugin.class }, new Object[] { this })) {
|
||||
componentManager.add(component);
|
||||
}
|
||||
Log.info("Loaded " + componentManager.components.size() + " components.");
|
||||
Log.verboseinfo("Loaded " + componentManager.components.size() + " components.");
|
||||
|
||||
registerEvents();
|
||||
|
||||
@@ -129,10 +136,14 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
int port = configuration.getInteger("webserver-port", 8123);
|
||||
|
||||
boolean allow_symlinks = configuration.getBoolean("allow-symlinks", false);
|
||||
if(allow_symlinks)
|
||||
Log.verboseinfo("Web server is permitting symbolic links");
|
||||
else
|
||||
Log.verboseinfo("Web server is not permitting symbolic links");
|
||||
webServer = new HttpServer(bindAddress, port);
|
||||
webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web"))));
|
||||
webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory));
|
||||
webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web")), allow_symlinks));
|
||||
webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory, allow_symlinks));
|
||||
webServer.handlers.put("/up/configuration", new ClientConfigurationHandler(this));
|
||||
}
|
||||
|
||||
@@ -180,11 +191,35 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
BlockListener renderTrigger = new BlockListener() {
|
||||
@Override
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
mm.touch(event.getBlockPlaced().getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
mm.touch(event.getBlock().getLocation());
|
||||
}
|
||||
@Override
|
||||
public void onSnowForm(SnowFormEvent event) {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
mm.touch(event.getBlock().getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeavesDecay(LeavesDecayEvent event) {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
mm.touch(event.getBlock().getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBurn(BlockBurnEvent event) {
|
||||
if(event.isCancelled())
|
||||
return;
|
||||
mm.touch(event.getBlock().getLocation());
|
||||
}
|
||||
};
|
||||
@@ -192,6 +227,12 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
pm.registerEvent(org.bukkit.event.Event.Type.BLOCK_PLACE, renderTrigger, org.bukkit.event.Event.Priority.Monitor, this);
|
||||
if (isTrigger("blockbreak"))
|
||||
pm.registerEvent(org.bukkit.event.Event.Type.BLOCK_BREAK, renderTrigger, org.bukkit.event.Event.Priority.Monitor, this);
|
||||
if (isTrigger("snowform"))
|
||||
pm.registerEvent(org.bukkit.event.Event.Type.SNOW_FORM, renderTrigger, org.bukkit.event.Event.Priority.Monitor, this);
|
||||
if (isTrigger("leavesdecay"))
|
||||
pm.registerEvent(org.bukkit.event.Event.Type.LEAVES_DECAY, renderTrigger, org.bukkit.event.Event.Priority.Monitor, this);
|
||||
if (isTrigger("blockburn"))
|
||||
pm.registerEvent(org.bukkit.event.Event.Type.BLOCK_BURN, renderTrigger, org.bukkit.event.Event.Priority.Monitor, this);
|
||||
}
|
||||
{
|
||||
PlayerListener renderTrigger = new PlayerListener() {
|
||||
@@ -214,21 +255,46 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
WorldListener renderTrigger = new WorldListener() {
|
||||
@Override
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
int x = event.getChunk().getX() * 16 + 8;
|
||||
int z = event.getChunk().getZ() * 16 + 8;
|
||||
mm.touch(new Location(event.getWorld(), x, 127, z));
|
||||
if(ignore_chunk_loads)
|
||||
return;
|
||||
if(generate_only) {
|
||||
if(!isNewChunk(event))
|
||||
return;
|
||||
/* Touch extreme corners */
|
||||
int x = event.getChunk().getX() * 16;
|
||||
int z = event.getChunk().getZ() * 16;
|
||||
mm.touch(new Location(event.getWorld(), x, 0, z));
|
||||
mm.touch(new Location(event.getWorld(), x+15, 127, z));
|
||||
mm.touch(new Location(event.getWorld(), x+15, 0, z+15));
|
||||
mm.touch(new Location(event.getWorld(), x, 127, z+15));
|
||||
}
|
||||
else {
|
||||
int x = event.getChunk().getX() * 16 + 8;
|
||||
int z = event.getChunk().getZ() * 16 + 8;
|
||||
mm.touch(new Location(event.getWorld(), x, 127, z));
|
||||
}
|
||||
}
|
||||
private boolean isNewChunk(ChunkLoadEvent event) {
|
||||
return event.isNewChunk();
|
||||
}
|
||||
|
||||
/*
|
||||
* @Override public void onChunkGenerated(ChunkLoadEvent event)
|
||||
* { int x = event.getChunk().getX() * 16 + 8; int z =
|
||||
* event.getChunk().getZ() * 16 + 8; mm.touch(new
|
||||
* Location(event.getWorld(), x, 127, z)); }
|
||||
*/
|
||||
};
|
||||
if (isTrigger("chunkloaded"))
|
||||
boolean ongenerate = isTrigger("chunkgenerated");
|
||||
if(ongenerate) {
|
||||
try { /* Test if new enough bukkit to allow this */
|
||||
ChunkLoadEvent.class.getDeclaredMethod("isNewChunk", new Class[0]);
|
||||
} catch (NoSuchMethodException nsmx) {
|
||||
Log.info("Warning: CraftBukkit build does not support function needed for 'chunkgenerated' trigger - disabling");
|
||||
ongenerate = false;
|
||||
}
|
||||
}
|
||||
if(isTrigger("chunkloaded")) {
|
||||
generate_only = false;
|
||||
pm.registerEvent(org.bukkit.event.Event.Type.CHUNK_LOAD, renderTrigger, org.bukkit.event.Event.Priority.Monitor, this);
|
||||
//if (isTrigger("chunkgenerated")) pm.registerEvent(Event.Type.CHUNK_GENERATED, renderTrigger, Priority.Monitor, this);
|
||||
}
|
||||
else if(ongenerate) {
|
||||
generate_only = true;
|
||||
pm.registerEvent(org.bukkit.event.Event.Type.CHUNK_LOAD, renderTrigger, org.bukkit.event.Event.Priority.Monitor, this);
|
||||
}
|
||||
}
|
||||
|
||||
// To link configuration to real loaded worlds.
|
||||
@@ -330,14 +396,14 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
World w = getServer().getWorld(args[i]);
|
||||
if(w != null)
|
||||
mapManager.renderFullWorld(new Location(w, 0, 0, 0));
|
||||
mapManager.renderFullWorld(new Location(w, 0, 0, 0),sender);
|
||||
else
|
||||
sender.sendMessage("World '" + args[i] + "' not defined/loaded");
|
||||
}
|
||||
} else if (player != null) {
|
||||
Location loc = player.getLocation();
|
||||
if(loc != null)
|
||||
mapManager.renderFullWorld(loc);
|
||||
mapManager.renderFullWorld(loc, sender);
|
||||
} else {
|
||||
sender.sendMessage("World name is required");
|
||||
}
|
||||
@@ -396,9 +462,9 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
finalConfiguration.extend(templateConfiguration);
|
||||
finalConfiguration.extend(worldConfiguration);
|
||||
|
||||
Log.info("Configuration of world " + world.getName());
|
||||
Log.verboseinfo("Configuration of world " + world.getName());
|
||||
for(Map.Entry<String, Object> e : finalConfiguration.entrySet()) {
|
||||
Log.info(e.getKey() + ": " + e.getValue());
|
||||
Log.verboseinfo(e.getKey() + ": " + e.getValue());
|
||||
}
|
||||
|
||||
return finalConfiguration;
|
||||
@@ -407,7 +473,7 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
private ConfigurationNode getDefaultTemplateConfigurationNode(World world) {
|
||||
Environment environment = world.getEnvironment();
|
||||
String environmentName = environment.name().toLowerCase();
|
||||
Log.info("Using environment as template: " + environmentName);
|
||||
Log.verboseinfo("Using environment as template: " + environmentName);
|
||||
return getTemplateConfigurationNode(environmentName);
|
||||
}
|
||||
|
||||
@@ -433,4 +499,12 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
pluginManager.disablePlugin(this);
|
||||
pluginManager.enablePlugin(this);
|
||||
}
|
||||
|
||||
public String getWebPath() {
|
||||
return configuration.getString("webpath", "web");
|
||||
}
|
||||
|
||||
public static void setIgnoreChunkLoads(boolean ignore) {
|
||||
ignore_chunk_loads = ignore;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,359 @@ import java.util.List;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.Location;
|
||||
import org.dynmap.debug.Debug;
|
||||
import org.dynmap.kzedmap.KzedMap;
|
||||
import org.dynmap.kzedmap.KzedMap.KzedBufferedImage;
|
||||
import org.dynmap.utils.FileLockManager;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class DynmapWorld {
|
||||
public enum AutoGenerateOption {
|
||||
NONE,
|
||||
FORMAPONLY,
|
||||
PERMANENT
|
||||
}
|
||||
public World world;
|
||||
public List<MapType> maps = new ArrayList<MapType>();
|
||||
public UpdateQueue updates = new UpdateQueue();
|
||||
public ConfigurationNode configuration;
|
||||
public List<Location> seedloc;
|
||||
public List<MapChunkCache.VisibilityLimit> visibility_limits;
|
||||
public AutoGenerateOption do_autogenerate;
|
||||
public MapChunkCache.HiddenChunkStyle hiddenchunkstyle;
|
||||
public int servertime;
|
||||
public boolean sendposition;
|
||||
public boolean sendhealth;
|
||||
public boolean bigworld; /* If true, deeper directory hierarchy */
|
||||
private int extrazoomoutlevels; /* Number of additional zoom out levels to generate */
|
||||
public File worldtilepath;
|
||||
private Object lock = new Object();
|
||||
private HashSet<String> zoomoutupdates[];
|
||||
private boolean checkts = true; /* Check timestamps on first run with new configuration */
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setExtraZoomOutLevels(int lvl) {
|
||||
extrazoomoutlevels = lvl;
|
||||
zoomoutupdates = new HashSet[lvl];
|
||||
for(int i = 0; i < lvl; i++)
|
||||
zoomoutupdates[i] = new HashSet<String>();
|
||||
checkts = true;
|
||||
}
|
||||
public int getExtraZoomOutLevels() { return extrazoomoutlevels; }
|
||||
|
||||
public void enqueueZoomOutUpdate(File f) {
|
||||
enqueueZoomOutUpdate(f, 0);
|
||||
}
|
||||
|
||||
private void enqueueZoomOutUpdate(File f, int level) {
|
||||
if(level >= extrazoomoutlevels)
|
||||
return;
|
||||
synchronized(lock) {
|
||||
zoomoutupdates[level].add(f.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean popQueuedUpdate(File f, int level) {
|
||||
if(level >= extrazoomoutlevels)
|
||||
return false;
|
||||
synchronized(lock) {
|
||||
return zoomoutupdates[level].remove(f.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private static class DirFilter implements FilenameFilter {
|
||||
public boolean accept(File f, String n) {
|
||||
if(!n.equals("..") && !n.equals(".")) {
|
||||
File fn = new File(f, n);
|
||||
return fn.isDirectory();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PNGFileFilter implements FilenameFilter {
|
||||
String prefix;
|
||||
public PNGFileFilter(String pre) { prefix = pre; }
|
||||
public boolean accept(File f, String n) {
|
||||
if(n.endsWith(".png") && n.startsWith(prefix)) {
|
||||
File fn = new File(f, n);
|
||||
return fn.isFile();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void freshenZoomOutFiles() {
|
||||
for(int i = 0; i < extrazoomoutlevels; i++) {
|
||||
freshenZoomOutFilesByLevel(i);
|
||||
}
|
||||
checkts = false; /* Just handle queued updates after first scan */
|
||||
}
|
||||
|
||||
private static class PrefixData {
|
||||
int stepsize;
|
||||
int[] stepseq;
|
||||
boolean neg_step_x;
|
||||
String baseprefix;
|
||||
int zoomlevel;
|
||||
String zoomprefix;
|
||||
String fnprefix;
|
||||
String zfnprefix;
|
||||
int bigworldshift;
|
||||
}
|
||||
|
||||
public void freshenZoomOutFilesByLevel(int zoomlevel) {
|
||||
int cnt = 0;
|
||||
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ")");
|
||||
if(worldtilepath.exists() == false) /* Quit if not found */
|
||||
return;
|
||||
HashMap<String, PrefixData> maptab = buildPrefixData(zoomlevel);
|
||||
|
||||
if(bigworld) { /* If big world, next directories are map name specific */
|
||||
DirFilter df = new DirFilter();
|
||||
for(String pfx : maptab.keySet()) { /* Walk through prefixes, as directories */
|
||||
PrefixData pd = maptab.get(pfx);
|
||||
File dname = new File(worldtilepath, pfx);
|
||||
/* Now, go through subdirectories under this one, and process them */
|
||||
String[] subdir = dname.list(df);
|
||||
if(subdir == null) continue;
|
||||
for(String s : subdir) {
|
||||
File sdname = new File(dname, s);
|
||||
cnt += processZoomDirectory(sdname, pd);
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* Else, classic file layout */
|
||||
for(String pfx : maptab.keySet()) { /* Walk through prefixes, as directories */
|
||||
cnt += processZoomDirectory(worldtilepath, maptab.get(pfx));
|
||||
}
|
||||
}
|
||||
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ") - done (" + cnt + " updated files)");
|
||||
}
|
||||
|
||||
private HashMap<String, PrefixData> buildPrefixData(int zoomlevel) {
|
||||
HashMap<String, PrefixData> maptab = new HashMap<String, PrefixData>();
|
||||
/* Build table of file prefixes and step sizes */
|
||||
for(MapType mt : maps) {
|
||||
List<String> pfx = mt.baseZoomFilePrefixes();
|
||||
int stepsize = mt.baseZoomFileStepSize();
|
||||
int bigworldshift = mt.getBigWorldShift();
|
||||
boolean neg_step_x = false;
|
||||
if(stepsize < 0) {
|
||||
stepsize = -stepsize;
|
||||
neg_step_x = true;
|
||||
}
|
||||
int[] stepseq = mt.zoomFileStepSequence();
|
||||
for(String p : pfx) {
|
||||
PrefixData pd = new PrefixData();
|
||||
pd.stepsize = stepsize;
|
||||
pd.neg_step_x = neg_step_x;
|
||||
pd.stepseq = stepseq;
|
||||
pd.baseprefix = p;
|
||||
pd.zoomlevel = zoomlevel;
|
||||
pd.zoomprefix = "zzzzzzzzzzzz".substring(0, zoomlevel);
|
||||
pd.bigworldshift = bigworldshift;
|
||||
if(bigworld) {
|
||||
if(zoomlevel > 0) {
|
||||
pd.zoomprefix += "_";
|
||||
pd.zfnprefix = "z" + pd.zoomprefix;
|
||||
}
|
||||
else {
|
||||
pd.zfnprefix = "z_";
|
||||
}
|
||||
pd.fnprefix = pd.zoomprefix;
|
||||
}
|
||||
else {
|
||||
pd.fnprefix = pd.zoomprefix + pd.baseprefix;
|
||||
pd.zfnprefix = "z" + pd.fnprefix;
|
||||
}
|
||||
|
||||
maptab.put(p, pd);
|
||||
}
|
||||
}
|
||||
return maptab;
|
||||
}
|
||||
|
||||
private static class ProcessTileRec {
|
||||
File zf;
|
||||
String zfname;
|
||||
int x, y;
|
||||
}
|
||||
|
||||
private String makeFilePath(PrefixData pd, int x, int y, boolean zoomed) {
|
||||
if(bigworld)
|
||||
return pd.baseprefix + "/" + (x >> pd.bigworldshift) + "_" + (y >> pd.bigworldshift) + "/" + (zoomed?pd.zfnprefix:pd.fnprefix) + x + "_" + y + ".png";
|
||||
else
|
||||
return (zoomed?pd.zfnprefix:pd.fnprefix) + "_" + x + "_" + y + ".png";
|
||||
}
|
||||
|
||||
private int processZoomDirectory(File dir, PrefixData pd) {
|
||||
Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ")");
|
||||
HashMap<String, ProcessTileRec> toprocess = new HashMap<String, ProcessTileRec>();
|
||||
String[] files = dir.list(new PNGFileFilter(pd.fnprefix));
|
||||
if(files == null)
|
||||
return 0;
|
||||
for(String fn : files) {
|
||||
ProcessTileRec tr = processZoomFile(new File(dir, fn), pd);
|
||||
if(tr != null) {
|
||||
String zfpath = tr.zf.getPath();
|
||||
if(!toprocess.containsKey(zfpath)) {
|
||||
toprocess.put(zfpath, tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
int cnt = 0;
|
||||
/* Do processing */
|
||||
for(ProcessTileRec s : toprocess.values()) {
|
||||
processZoomTile(pd, dir, s.zf, s.zfname, s.x, s.y);
|
||||
cnt++;
|
||||
}
|
||||
Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ") - done (" + cnt + " files)");
|
||||
return cnt;
|
||||
}
|
||||
|
||||
private ProcessTileRec processZoomFile(File f, PrefixData pd) {
|
||||
/* If not checking timstamp, we're out if nothing queued for this file */
|
||||
if(!checkts) {
|
||||
if(!popQueuedUpdate(f, pd.zoomlevel))
|
||||
return null;
|
||||
}
|
||||
int step = pd.stepsize << pd.zoomlevel;
|
||||
String fn = f.getName();
|
||||
/* Parse filename to predict zoomed out file */
|
||||
fn = fn.substring(0, fn.lastIndexOf('.')); /* Strip off extension */
|
||||
String[] tok = fn.split("_"); /* Split by underscores */
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
boolean parsed = false;
|
||||
if(tok.length >= 2) {
|
||||
try {
|
||||
x = Integer.parseInt(tok[tok.length-2]);
|
||||
y = Integer.parseInt(tok[tok.length-1]);
|
||||
parsed = true;
|
||||
} catch (NumberFormatException nfx) {
|
||||
}
|
||||
}
|
||||
if(!parsed)
|
||||
return null;
|
||||
if(pd.neg_step_x) x = -x;
|
||||
if(x >= 0)
|
||||
x = x - (x % (2*step));
|
||||
else
|
||||
x = x + (x % (2*step));
|
||||
if(pd.neg_step_x) x = -x;
|
||||
if(y >= 0)
|
||||
y = y - (y % (2*step));
|
||||
else
|
||||
y = y + (y % (2*step));
|
||||
/* Make name of corresponding zoomed tile */
|
||||
String zfname = makeFilePath(pd, x, y, true);
|
||||
File zf = new File(worldtilepath, zfname);
|
||||
if(checkts) { /* If checking timestamp, see if we need update based on enqueued update OR old file time */
|
||||
/* If we're not updated, and zoom file exists and is older than our file, nothing to do */
|
||||
if((!popQueuedUpdate(f, pd.zoomlevel)) && zf.exists() && (zf.lastModified() >= f.lastModified())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
ProcessTileRec rec = new ProcessTileRec();
|
||||
rec.zf = zf;
|
||||
rec.x = x;
|
||||
rec.y = y;
|
||||
rec.zfname = zfname;
|
||||
Debug.debug("Process " + zf.getPath() + " due to " + f.getPath());
|
||||
return rec;
|
||||
}
|
||||
|
||||
private void processZoomTile(PrefixData pd, File dir, File zf, String zfname, int tx, int ty) {
|
||||
Debug.debug("processZoomFile(" + pd.baseprefix + "," + dir.getPath() + "," + zf.getPath() + "," + tx + "," + ty + ")");
|
||||
int width = 128, height = 128;
|
||||
BufferedImage zIm = null;
|
||||
KzedBufferedImage kzIm = null;
|
||||
int[] argb = new int[width*height];
|
||||
int step = pd.stepsize << pd.zoomlevel;
|
||||
int ztx = tx;
|
||||
tx = tx - (pd.neg_step_x?step:0); /* Adjust for negative step */
|
||||
|
||||
/* create image buffer */
|
||||
kzIm = KzedMap.allocateBufferedImage(width, height);
|
||||
zIm = kzIm.buf_img;
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
File f = new File(worldtilepath, makeFilePath(pd, (tx + step*(1&pd.stepseq[i])), (ty + step*(pd.stepseq[i]>>1)), false));
|
||||
if(f.exists()) {
|
||||
BufferedImage im = null;
|
||||
FileLockManager.getReadLock(f);
|
||||
popQueuedUpdate(f, pd.zoomlevel);
|
||||
try {
|
||||
im = ImageIO.read(f);
|
||||
} catch (IOException e) {
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
} finally {
|
||||
FileLockManager.releaseReadLock(f);
|
||||
}
|
||||
if(im != null) {
|
||||
im.getRGB(0, 0, width, height, argb, 0, width); /* Read data */
|
||||
im.flush();
|
||||
/* Do binlinear scale to 64x64 */
|
||||
Color c1 = new Color();
|
||||
for(int y = 0; y < height; y += 2) {
|
||||
for(int x = 0; x < width; x += 2) {
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
int alpha = 0;
|
||||
for(int yy = y; yy < y+2; yy++) {
|
||||
for(int xx = x; xx < x+2; xx++) {
|
||||
c1.setARGB(argb[(yy*width)+xx]);
|
||||
red += c1.getRed();
|
||||
green += c1.getGreen();
|
||||
blue += c1.getBlue();
|
||||
alpha += c1.getAlpha();
|
||||
}
|
||||
}
|
||||
c1.setRGBA(red>>2, green>>2, blue>>2, alpha>>2);
|
||||
argb[(y*width/2) + (x/2)] = c1.getARGB();
|
||||
}
|
||||
}
|
||||
/* blit scaled rendered tile onto zoom-out tile */
|
||||
zIm.setRGB(((i>>1) != 0)?0:width/2, (i & 1) * height/2, width/2, height/2, argb, 0, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
FileLockManager.getWriteLock(zf);
|
||||
try {
|
||||
TileHashManager hashman = MapManager.mapman.hashman;
|
||||
long crc = hashman.calculateTileHash(kzIm.argb_buf); /* Get hash of tile */
|
||||
int tilex = ztx/step/2;
|
||||
int tiley = ty/step/2;
|
||||
String key = world.getName()+".z"+pd.zoomprefix+pd.baseprefix;
|
||||
if((!zf.exists()) || (crc != MapManager.mapman.hashman.getImageHashCode(key, null, tilex, tiley))) {
|
||||
try {
|
||||
if(!zf.getParentFile().exists())
|
||||
zf.getParentFile().mkdirs();
|
||||
FileLockManager.imageIOWrite(zIm, "png", zf);
|
||||
Debug.debug("Saved zoom-out tile at " + zf.getPath());
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zf.getName(), e);
|
||||
}
|
||||
hashman.updateHashCode(key, null, tilex, tiley, crc);
|
||||
MapManager.mapman.pushUpdate(this.world, new Client.Tile(zfname));
|
||||
enqueueZoomOutUpdate(zf, pd.zoomlevel+1);
|
||||
}
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(zf);
|
||||
KzedMap.freeBufferedImage(kzIm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.Map;
|
||||
|
||||
public class Events {
|
||||
public Map<String, Event<?>> events = new HashMap<String, Event<?>>();
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void addListener(String eventName, Event.Listener<T> listener) {
|
||||
Event<?> genericEvent = events.get(eventName);
|
||||
Event<T> event = null;
|
||||
@@ -16,6 +17,7 @@ public class Events {
|
||||
event.addListener(listener);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void removeListener(String eventName, Event.Listener<T> listener) {
|
||||
Event<?> genericEvent = events.get(eventName);
|
||||
Event<T> event = null;
|
||||
@@ -25,6 +27,7 @@ public class Events {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void trigger(String eventName, T argument) {
|
||||
Event<?> genericEvent = events.get(eventName);
|
||||
if (genericEvent == null)
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.dynmap;
|
||||
import org.dynmap.Event.Listener;
|
||||
import org.dynmap.web.handlers.ClientUpdateHandler;
|
||||
import org.dynmap.web.handlers.SendMessageHandler;
|
||||
import org.dynmap.web.handlers.SendMessageHandler.Message;
|
||||
import org.json.simple.JSONObject;
|
||||
import static org.dynmap.JSONUtils.*;
|
||||
|
||||
@@ -13,6 +12,7 @@ public class InternalClientUpdateComponent extends ClientUpdateComponent {
|
||||
super(plugin, configuration);
|
||||
final Boolean allowwebchat = configuration.getBoolean("allowwebchat", false);
|
||||
final Boolean hidewebchatip = configuration.getBoolean("hidewebchatip", false);
|
||||
final Boolean trust_client_name = configuration.getBoolean("trustclientname", false);
|
||||
final float webchatInterval = configuration.getFloat("webchat-interval", 1);
|
||||
final String spammessage = plugin.configuration.getString("spammessage", "You may only chat once every %interval% seconds.");
|
||||
|
||||
@@ -31,6 +31,7 @@ public class InternalClientUpdateComponent extends ClientUpdateComponent {
|
||||
maximumMessageInterval = (int)(webchatInterval * 1000);
|
||||
spamMessage = "\""+spammessage+"\"";
|
||||
hideip = hidewebchatip;
|
||||
this.trustclientname = trust_client_name;
|
||||
onMessageReceived.addListener(new Listener<SendMessageHandler.Message>() {
|
||||
@Override
|
||||
public void triggered(Message t) {
|
||||
|
||||
@@ -25,6 +25,7 @@ public class JSONUtils {
|
||||
}
|
||||
|
||||
// Sets a value on the specified path. If JSONObjects inside the path are missing, they'll be created.
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void s(JSONObject o, String path, Object value) {
|
||||
int index = path.indexOf('/');
|
||||
if (index == -1) {
|
||||
@@ -45,6 +46,7 @@ public class JSONUtils {
|
||||
}
|
||||
|
||||
// Adds a value to the list at the specified path. If the list does not exist, it will be created.
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void a(JSONObject o, String path, Object value) {
|
||||
Object oo = g(o, path);
|
||||
JSONArray array;
|
||||
@@ -58,6 +60,7 @@ public class JSONUtils {
|
||||
}
|
||||
|
||||
// Simply creates a JSONArray.
|
||||
@SuppressWarnings("unchecked")
|
||||
public static JSONArray l(Object... items) {
|
||||
JSONArray arr = new JSONArray();
|
||||
for(Object item : items) {
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.dynmap;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.Reader;
|
||||
@@ -13,9 +12,7 @@ import java.util.Iterator;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.dynmap.web.Json;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
@@ -105,6 +102,7 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void writeUpdates() {
|
||||
File outputFile;
|
||||
File outputTempFile;
|
||||
|
||||
@@ -6,9 +6,14 @@ import java.util.logging.Logger;
|
||||
public class Log {
|
||||
protected static final Logger log = Logger.getLogger("Minecraft");
|
||||
protected static final String LOG_PREFIX = "[dynmap] ";
|
||||
public static boolean verbose = false;
|
||||
public static void info(String msg) {
|
||||
log.log(Level.INFO, LOG_PREFIX + msg);
|
||||
}
|
||||
public static void verboseinfo(String msg) {
|
||||
if(verbose)
|
||||
log.log(Level.INFO, LOG_PREFIX + msg);
|
||||
}
|
||||
public static void severe(Exception e) {
|
||||
log.log(Level.SEVERE, LOG_PREFIX + "Exception occured: ", e);
|
||||
}
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
package org.dynmap;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedList;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
/**
|
||||
* Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread
|
||||
*/
|
||||
public class MapChunkCache {
|
||||
private World w;
|
||||
private static Method getchunkdata = null;
|
||||
private static Method gethandle = null;
|
||||
private static Method poppreservedchunk = null;
|
||||
private static Field heightmap = null;
|
||||
private static boolean initialized = false;
|
||||
|
||||
private int x_min, x_max, z_min, z_max;
|
||||
private int x_dim;
|
||||
|
||||
private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */
|
||||
|
||||
/**
|
||||
* Iterator for traversing map chunk cache (base is for non-snapshot)
|
||||
*/
|
||||
public class MapIterator {
|
||||
public int x, y, z;
|
||||
private ChunkSnapshot snap;
|
||||
|
||||
MapIterator(int x0, int y0, int z0) {
|
||||
initialize(x0, y0, z0);
|
||||
}
|
||||
public final void initialize(int x0, int y0, int z0) {
|
||||
this.x = x0;
|
||||
this.y = y0;
|
||||
this.z = z0;
|
||||
try {
|
||||
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
} catch (ArrayIndexOutOfBoundsException aioobx) {
|
||||
snap = EMPTY;
|
||||
}
|
||||
}
|
||||
public final int getBlockTypeID() {
|
||||
return snap.getBlockTypeId(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
public final int getBlockData() {
|
||||
return snap.getBlockData(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
public final int getHighestBlockYAt() {
|
||||
return snap.getHighestBlockYAt(x & 0xF, z & 0xF);
|
||||
}
|
||||
public final int getBlockSkyLight() {
|
||||
return snap.getBlockSkyLight(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
public final int getBlockEmittedLight() {
|
||||
return snap.getBlockEmittedLight(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
public final void incrementX() {
|
||||
x++;
|
||||
if((x & 0xF) == 0) { /* Next chunk? */
|
||||
try {
|
||||
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
} catch (ArrayIndexOutOfBoundsException aioobx) {
|
||||
snap = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
public final void decrementX() {
|
||||
x--;
|
||||
if((x & 0xF) == 15) { /* Next chunk? */
|
||||
try {
|
||||
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
} catch (ArrayIndexOutOfBoundsException aioobx) {
|
||||
snap = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
public final void incrementY() {
|
||||
y++;
|
||||
}
|
||||
public final void decrementY() {
|
||||
y--;
|
||||
}
|
||||
public final void incrementZ() {
|
||||
z++;
|
||||
if((z & 0xF) == 0) { /* Next chunk? */
|
||||
try {
|
||||
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
} catch (ArrayIndexOutOfBoundsException aioobx) {
|
||||
snap = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
public final void decrementZ() {
|
||||
z--;
|
||||
if((z & 0xF) == 15) { /* Next chunk? */
|
||||
try {
|
||||
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
} catch (ArrayIndexOutOfBoundsException aioobx) {
|
||||
snap = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
public final void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Chunk cache for representing unloaded chunk
|
||||
*/
|
||||
private static class EmptyChunk implements ChunkSnapshot {
|
||||
public final int getBlockTypeId(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
public final int getBlockData(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
public final int getBlockSkyLight(int x, int y, int z) {
|
||||
return 15;
|
||||
}
|
||||
public final int getBlockEmittedLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
public final int getHighestBlockYAt(int x, int z) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static final EmptyChunk EMPTY = new EmptyChunk();
|
||||
/**
|
||||
* Create chunk cache container
|
||||
* @param w - world
|
||||
* @param x_min - minimum chunk x coordinate
|
||||
* @param z_min - minimum chunk z coordinate
|
||||
* @param x_max - maximum chunk x coordinate
|
||||
* @param z_max - maximum chunk z coordinate
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public MapChunkCache(World w, DynmapChunk[] chunks) {
|
||||
/* Compute range */
|
||||
if(chunks.length == 0) {
|
||||
this.x_min = 0;
|
||||
this.x_max = 0;
|
||||
this.z_min = 0;
|
||||
this.z_max = 0;
|
||||
x_dim = 1;
|
||||
}
|
||||
else {
|
||||
x_min = x_max = chunks[0].x;
|
||||
z_min = z_max = chunks[0].z;
|
||||
for(int i = 1; i < chunks.length; i++) {
|
||||
if(chunks[i].x > x_max)
|
||||
x_max = chunks[i].x;
|
||||
if(chunks[i].x < x_min)
|
||||
x_min = chunks[i].x;
|
||||
if(chunks[i].z > z_max)
|
||||
z_max = chunks[i].z;
|
||||
if(chunks[i].z < z_min)
|
||||
z_min = chunks[i].z;
|
||||
}
|
||||
x_dim = x_max - x_min + 1;
|
||||
}
|
||||
this.w = w;
|
||||
|
||||
if(!initialized) {
|
||||
try {
|
||||
Class c = Class.forName("net.minecraft.server.Chunk");
|
||||
getchunkdata = c.getDeclaredMethod("a", new Class[] { byte[].class, int.class,
|
||||
int.class, int.class, int.class, int.class, int.class, int.class });
|
||||
heightmap = c.getDeclaredField("h");
|
||||
c = Class.forName("org.bukkit.craftbukkit.CraftChunk");
|
||||
gethandle = c.getDeclaredMethod("getHandle", new Class[0]);
|
||||
} catch (ClassNotFoundException cnfx) {
|
||||
} catch (NoSuchMethodException nsmx) {
|
||||
} catch (NoSuchFieldException nsfx) {
|
||||
}
|
||||
/* Get CraftWorld.popPreservedChunk(x,z) - reduces memory bloat from map traversals (optional) */
|
||||
try {
|
||||
Class c = Class.forName("org.bukkit.craftbukkit.CraftWorld");
|
||||
poppreservedchunk = c.getDeclaredMethod("popPreservedChunk", new Class[] { int.class, int.class });
|
||||
} catch (ClassNotFoundException cnfx) {
|
||||
} catch (NoSuchMethodException nsmx) {
|
||||
}
|
||||
initialized = true;
|
||||
if(gethandle != null)
|
||||
Log.info("Chunk snapshot support enabled");
|
||||
else {
|
||||
Log.severe("ERROR: Chunk snapshot support not found - rendering not functiona!l");
|
||||
return;
|
||||
}
|
||||
}
|
||||
snaparray = new ChunkSnapshot[x_dim * (z_max-z_min+1)];
|
||||
if(gethandle != null) {
|
||||
// Load the required chunks.
|
||||
for (DynmapChunk chunk : chunks) {
|
||||
boolean wasLoaded = w.isChunkLoaded(chunk.x, chunk.z);
|
||||
boolean didload = w.loadChunk(chunk.x, chunk.z, false);
|
||||
/* If it did load, make cache of it */
|
||||
if(didload) {
|
||||
Chunk c = w.getChunkAt(chunk.x, chunk.z);
|
||||
try {
|
||||
Object cc = gethandle.invoke(c);
|
||||
byte[] buf = new byte[32768 + 16384 + 16384 + 16384]; /* Get big enough buffer for whole chunk */
|
||||
getchunkdata.invoke(cc, buf, 0, 0, 0, 16, 128, 16, 0);
|
||||
byte[] h = (byte[])heightmap.get(cc);
|
||||
byte[] hmap = new byte[256];
|
||||
System.arraycopy(h, 0, hmap, 0, 256);
|
||||
CraftChunkSnapshot ss = new CraftChunkSnapshot(chunk.x, chunk.z, buf, hmap);
|
||||
snaparray[(chunk.x-x_min) + (chunk.z - z_min)*x_dim] = ss;
|
||||
} catch (Exception x) {
|
||||
}
|
||||
}
|
||||
if ((!wasLoaded) && didload) {
|
||||
/* It looks like bukkit "leaks" entities - they don't get removed from the world-level table
|
||||
* when chunks are unloaded but not saved - removing them seems to do the trick */
|
||||
Chunk cc = w.getChunkAt(chunk.x, chunk.z);
|
||||
if(cc != null) {
|
||||
for(Entity e: cc.getEntities())
|
||||
e.remove();
|
||||
}
|
||||
/* Since we only remember ones we loaded, and we're synchronous, no player has
|
||||
* moved, so it must be safe (also prevent chunk leak, which appears to happen
|
||||
* because isChunkInUse defined "in use" as being within 256 blocks of a player,
|
||||
* while the actual in-use chunk area for a player where the chunks are managed
|
||||
* by the MC base server is 21x21 (or about a 160 block radius) */
|
||||
w.unloadChunk(chunk.x, chunk.z, false, false);
|
||||
/* And pop preserved chunk - this is a bad leak in Bukkit for map traversals like us */
|
||||
try {
|
||||
if(poppreservedchunk != null)
|
||||
poppreservedchunk.invoke(w, chunk.x, chunk.z);
|
||||
} catch (Exception x) {
|
||||
Log.severe("Cannot pop preserved chunk - " + x.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Fill missing chunks with empty dummy chunk */
|
||||
for(int i = 0; i < snaparray.length; i++) {
|
||||
if(snaparray[i] == null)
|
||||
snaparray[i] = EMPTY;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Unload chunks
|
||||
*/
|
||||
public void unloadChunks() {
|
||||
if(snaparray != null) {
|
||||
for(int i = 0; i < snaparray.length; i++) {
|
||||
snaparray[i] = null;
|
||||
}
|
||||
snaparray = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get block ID at coordinates
|
||||
*/
|
||||
public int getBlockTypeID(int x, int y, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getBlockTypeId(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
/**
|
||||
* Get block data at coordiates
|
||||
*/
|
||||
public byte getBlockData(int x, int y, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return (byte)ss.getBlockData(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
/* Get highest block Y
|
||||
*
|
||||
*/
|
||||
public int getHighestBlockYAt(int x, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getHighestBlockYAt(x & 0xF, z & 0xF);
|
||||
}
|
||||
/* Get sky light level
|
||||
*/
|
||||
public int getBlockSkyLight(int x, int y, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getBlockSkyLight(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
/* Get emitted light level
|
||||
*/
|
||||
public int getBlockEmittedLight(int x, int y, int z) {
|
||||
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
|
||||
return ss.getBlockEmittedLight(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
/**
|
||||
* Get cache iterator
|
||||
*/
|
||||
public MapIterator getIterator(int x, int y, int z) {
|
||||
return new MapIterator(x, y, z);
|
||||
}
|
||||
}
|
||||
@@ -9,26 +9,39 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.dynmap.DynmapWorld.AutoGenerateOption;
|
||||
import org.dynmap.debug.Debug;
|
||||
import org.dynmap.utils.LegacyMapChunkCache;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.NewMapChunkCache;
|
||||
|
||||
public class MapManager {
|
||||
public AsynchronousQueue<MapTile> tileQueue;
|
||||
|
||||
private static final int DEFAULT_CHUNKS_PER_TICK = 200;
|
||||
private static final int DEFAULT_ZOOMOUT_PERIOD = 60;
|
||||
public List<DynmapWorld> worlds = new ArrayList<DynmapWorld>();
|
||||
public Map<String, DynmapWorld> worldsLookup = new HashMap<String, DynmapWorld>();
|
||||
private BukkitScheduler scheduler;
|
||||
private DynmapPlugin plug_in;
|
||||
private long timeslice_int = 0; /* In milliseconds */
|
||||
private int max_chunk_loads_per_tick = DEFAULT_CHUNKS_PER_TICK;
|
||||
|
||||
private int zoomout_period = DEFAULT_ZOOMOUT_PERIOD; /* Zoom-out tile processing period, in seconds */
|
||||
/* Which fullrenders are active */
|
||||
private HashMap<String, FullWorldRenderState> active_renders = new HashMap<String, FullWorldRenderState>();
|
||||
/* List of MapChunkCache requests to be processed */
|
||||
private ConcurrentLinkedQueue<MapChunkCache> chunkloads = new ConcurrentLinkedQueue<MapChunkCache>();
|
||||
/* Tile hash manager */
|
||||
public TileHashManager hashman;
|
||||
/* lock for our data structures */
|
||||
@@ -57,10 +70,22 @@ public class MapManager {
|
||||
public Collection<DynmapWorld> getWorlds() {
|
||||
return worlds;
|
||||
}
|
||||
|
||||
private static class OurThreadFactory implements ThreadFactory {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.setName("Dynmap Render Thread");
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
private class DynmapScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
|
||||
DynmapScheduledThreadPoolExecutor() {
|
||||
super(POOL_SIZE);
|
||||
this.setThreadFactory(new OurThreadFactory());
|
||||
}
|
||||
|
||||
protected void afterExecute(Runnable r, Throwable x) {
|
||||
@@ -72,6 +97,40 @@ public class MapManager {
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void execute(final Runnable r) {
|
||||
final Runnable rr = r;
|
||||
try {
|
||||
super.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
r.run();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Exception during render job: " + r);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException rxe) { /* Pool shutdown - nominal for reload or unload */
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(final Runnable command, long delay, TimeUnit unit) {
|
||||
try {
|
||||
return super.schedule(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
command.run();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Exception during render job: " + command);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, delay, unit);
|
||||
} catch (RejectedExecutionException rxe) {
|
||||
return null; /* Pool shut down when we reload or unload */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* This always runs on render pool threads - no bukkit calls from here */
|
||||
private class FullWorldRenderState implements Runnable {
|
||||
@@ -85,14 +144,17 @@ public class MapManager {
|
||||
MapTile tile0 = null;
|
||||
MapTile tile = null;
|
||||
int rendercnt = 0;
|
||||
CommandSender sender;
|
||||
long timeaccum;
|
||||
|
||||
/* Full world, all maps render */
|
||||
FullWorldRenderState(DynmapWorld dworld, Location l) {
|
||||
FullWorldRenderState(DynmapWorld dworld, Location l, CommandSender sender) {
|
||||
world = dworld;
|
||||
loc = l;
|
||||
found = new HashSet<MapTile>();
|
||||
rendered = new HashSet<MapTile>();
|
||||
renderQueue = new LinkedList<MapTile>();
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
/* Single tile render - used for incremental renders */
|
||||
@@ -119,15 +181,16 @@ public class MapManager {
|
||||
/* If render queue is empty, start next map */
|
||||
if(renderQueue.isEmpty()) {
|
||||
if(map_index >= 0) { /* Finished a map? */
|
||||
Log.info("Full render of map '" + world.maps.get(map_index).getClass().getSimpleName() + "' of world '" +
|
||||
world.world.getName() + "' completed - " + rendercnt + " tiles rendered.");
|
||||
double msecpertile = (double)timeaccum / (double)((rendercnt>0)?rendercnt:1);
|
||||
sender.sendMessage("Full render of map '" + world.maps.get(map_index).getClass().getSimpleName() + "' of world '" +
|
||||
world.world.getName() + "' completed - " + rendercnt + " tiles rendered (" + String.format("%.2f", msecpertile) + " msec/tile).");
|
||||
}
|
||||
found.clear();
|
||||
rendered.clear();
|
||||
rendercnt = 0;
|
||||
map_index++; /* Next map */
|
||||
if(map_index >= world.maps.size()) { /* Last one done? */
|
||||
Log.info("Full render of '" + world.world.getName() + "' finished.");
|
||||
sender.sendMessage("Full render of '" + world.world.getName() + "' finished.");
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
@@ -158,17 +221,21 @@ public class MapManager {
|
||||
}
|
||||
World w = world.world;
|
||||
/* Fetch chunk cache from server thread */
|
||||
DynmapChunk[] requiredChunks = tile.getMap().getRequiredChunks(tile);
|
||||
MapChunkCache cache = createMapChunkCache(w, requiredChunks);
|
||||
MapType mt = tile.getMap();
|
||||
List<DynmapChunk> requiredChunks = mt.getRequiredChunks(tile);
|
||||
MapChunkCache cache = createMapChunkCache(world, requiredChunks, mt.isBlockTypeDataNeeded(),
|
||||
mt.isHightestBlockYDataNeeded(), mt.isBiomeDataNeeded(),
|
||||
mt.isRawBiomeDataNeeded());
|
||||
if(cache == null) {
|
||||
cleanup();
|
||||
return; /* Cancelled/aborted */
|
||||
}
|
||||
if(tile0 != null) { /* Single tile? */
|
||||
render(cache, tile); /* Just render */
|
||||
if(cache.isEmpty() == false)
|
||||
render(cache, tile); /* Just render */
|
||||
}
|
||||
else {
|
||||
if (render(cache, tile)) {
|
||||
if ((cache.isEmpty() == false) && render(cache, tile)) {
|
||||
found.remove(tile);
|
||||
rendered.add(tile);
|
||||
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
|
||||
@@ -179,10 +246,14 @@ public class MapManager {
|
||||
}
|
||||
}
|
||||
found.remove(tile);
|
||||
rendercnt++;
|
||||
if((rendercnt % 100) == 0) {
|
||||
Log.info("Full render of map '" + world.maps.get(map_index).getClass().getSimpleName() + "' on world '" +
|
||||
w.getName() + "' in progress - " + rendercnt + " tiles rendered, " + renderQueue.size() + " tiles pending.");
|
||||
if(!cache.isEmpty()) {
|
||||
rendercnt++;
|
||||
timeaccum += System.currentTimeMillis() - tstart;
|
||||
if((rendercnt % 100) == 0) {
|
||||
double msecpertile = (double)timeaccum / (double)rendercnt;
|
||||
sender.sendMessage("Full render of map '" + world.maps.get(map_index).getClass().getSimpleName() + "' on world '" +
|
||||
w.getName() + "' in progress - " + rendercnt + " tiles rendered (" + String.format("%.2f", msecpertile) + " msec/tile).");
|
||||
}
|
||||
}
|
||||
}
|
||||
/* And unload what we loaded */
|
||||
@@ -217,6 +288,36 @@ public class MapManager {
|
||||
}
|
||||
}
|
||||
|
||||
private class ProcessChunkLoads implements Runnable {
|
||||
public void run() {
|
||||
int cnt = max_chunk_loads_per_tick;
|
||||
|
||||
while(cnt > 0) {
|
||||
MapChunkCache c = chunkloads.peek();
|
||||
if(c == null)
|
||||
return;
|
||||
cnt = cnt - c.loadChunks(cnt);
|
||||
if(c.isDoneLoading()) {
|
||||
chunkloads.poll();
|
||||
synchronized(c) {
|
||||
c.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DoZoomOutProcessing implements Runnable {
|
||||
public void run() {
|
||||
Debug.debug("DoZoomOutProcessing started");
|
||||
for(DynmapWorld w : worlds) {
|
||||
w.freshenZoomOutFiles();
|
||||
}
|
||||
renderpool.schedule(this, zoomout_period, TimeUnit.SECONDS);
|
||||
Debug.debug("DoZoomOutProcessing finished");
|
||||
}
|
||||
}
|
||||
|
||||
public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) {
|
||||
plug_in = plugin;
|
||||
mapman = this;
|
||||
@@ -230,7 +331,12 @@ public class MapManager {
|
||||
|
||||
/* On dedicated thread, so default to no delays */
|
||||
timeslice_int = (long)(configuration.getDouble("timesliceinterval", 0.0) * 1000);
|
||||
|
||||
max_chunk_loads_per_tick = configuration.getInteger("maxchunkspertick", DEFAULT_CHUNKS_PER_TICK);
|
||||
if(max_chunk_loads_per_tick < 5) max_chunk_loads_per_tick = 5;
|
||||
/* Get zoomout processing periond in seconds */
|
||||
zoomout_period = configuration.getInteger("zoomoutperiod", DEFAULT_ZOOMOUT_PERIOD);
|
||||
if(zoomout_period < 5) zoomout_period = 5;
|
||||
|
||||
scheduler = plugin.getServer().getScheduler();
|
||||
|
||||
hashman = new TileHashManager(DynmapPlugin.tilesDirectory, configuration.getBoolean("enabletilehash", true));
|
||||
@@ -242,13 +348,14 @@ public class MapManager {
|
||||
}
|
||||
|
||||
scheduler.scheduleSyncRepeatingTask(plugin, new CheckWorldTimes(), 5*20, 5*20); /* Check very 5 seconds */
|
||||
|
||||
scheduler.scheduleSyncRepeatingTask(plugin, new ProcessChunkLoads(), 1, 1); /* Chunk loader task */
|
||||
|
||||
}
|
||||
|
||||
void renderFullWorld(Location l) {
|
||||
void renderFullWorld(Location l, CommandSender sender) {
|
||||
DynmapWorld world = getWorld(l.getWorld().getName());
|
||||
if (world == null) {
|
||||
Log.severe("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration.");
|
||||
sender.sendMessage("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration.");
|
||||
return;
|
||||
}
|
||||
String wname = l.getWorld().getName();
|
||||
@@ -256,15 +363,15 @@ public class MapManager {
|
||||
synchronized(lock) {
|
||||
rndr = active_renders.get(wname);
|
||||
if(rndr != null) {
|
||||
Log.info("Full world render of world '" + wname + "' already active.");
|
||||
sender.sendMessage("Full world render of world '" + wname + "' already active.");
|
||||
return;
|
||||
}
|
||||
rndr = new FullWorldRenderState(world,l); /* Make new activation record */
|
||||
rndr = new FullWorldRenderState(world,l,sender); /* Make new activation record */
|
||||
active_renders.put(wname, rndr); /* Add to active table */
|
||||
}
|
||||
/* Schedule first tile to be worked */
|
||||
renderpool.execute(rndr);
|
||||
Log.info("Full render starting on world '" + wname + "'...");
|
||||
sender.sendMessage("Full render starting on world '" + wname + "'...");
|
||||
}
|
||||
|
||||
public void activateWorld(World w) {
|
||||
@@ -285,7 +392,7 @@ public class MapManager {
|
||||
DynmapWorld dynmapWorld = new DynmapWorld();
|
||||
dynmapWorld.world = w;
|
||||
dynmapWorld.configuration = worldConfiguration;
|
||||
Log.info("Loading maps of world '" + worldName + "'...");
|
||||
Log.verboseinfo("Loading maps of world '" + worldName + "'...");
|
||||
for(MapType map : worldConfiguration.<MapType>createInstances("maps", new Class<?>[0], new Object[0])) {
|
||||
map.onTileInvalidated.addListener(invalitateListener);
|
||||
dynmapWorld.maps.add(map);
|
||||
@@ -297,12 +404,52 @@ public class MapManager {
|
||||
dynmapWorld.servertime = (int)(w.getTime() % 24000);
|
||||
dynmapWorld.sendposition = worldConfiguration.getBoolean("sendposition", true);
|
||||
dynmapWorld.sendhealth = worldConfiguration.getBoolean("sendhealth", true);
|
||||
dynmapWorld.bigworld = worldConfiguration.getBoolean("bigworld", false);
|
||||
dynmapWorld.setExtraZoomOutLevels(worldConfiguration.getInteger("extrazoomout", 0));
|
||||
dynmapWorld.worldtilepath = new File(plug_in.tilesDirectory, w.getName());
|
||||
if(loclist != null) {
|
||||
for(ConfigurationNode loc : loclist) {
|
||||
Location lx = new Location(w, loc.getDouble("x", 0), loc.getDouble("y", 64), loc.getDouble("z", 0));
|
||||
dynmapWorld.seedloc.add(lx);
|
||||
}
|
||||
}
|
||||
/* Load visibility limits, if any are defined */
|
||||
List<ConfigurationNode> vislimits = worldConfiguration.getNodes("visibilitylimits");
|
||||
if(vislimits != null) {
|
||||
dynmapWorld.visibility_limits = new ArrayList<MapChunkCache.VisibilityLimit>();
|
||||
for(ConfigurationNode vis : vislimits) {
|
||||
MapChunkCache.VisibilityLimit lim = new MapChunkCache.VisibilityLimit();
|
||||
lim.x0 = vis.getInteger("x0", 0);
|
||||
lim.x1 = vis.getInteger("x1", 0);
|
||||
lim.z0 = vis.getInteger("z0", 0);
|
||||
lim.z1 = vis.getInteger("z1", 0);
|
||||
dynmapWorld.visibility_limits.add(lim);
|
||||
/* Also, add a seed location for the middle of each visible area */
|
||||
dynmapWorld.seedloc.add(new Location(w, (lim.x0+lim.x1)/2, 64, (lim.z0+lim.z1)/2));
|
||||
}
|
||||
}
|
||||
String autogen = worldConfiguration.getString("autogenerate-to-visibilitylimits", "none");
|
||||
if(autogen.equals("permanent")) {
|
||||
dynmapWorld.do_autogenerate = AutoGenerateOption.PERMANENT;
|
||||
}
|
||||
else if(autogen.equals("map-only")) {
|
||||
dynmapWorld.do_autogenerate = AutoGenerateOption.FORMAPONLY;
|
||||
}
|
||||
else {
|
||||
dynmapWorld.do_autogenerate = AutoGenerateOption.NONE;
|
||||
}
|
||||
if((dynmapWorld.do_autogenerate != AutoGenerateOption.NONE) && (dynmapWorld.visibility_limits == null)) {
|
||||
Log.info("Warning: Automatic world generation to visible limits option requires that visibitylimits be set - option disabled");
|
||||
dynmapWorld.do_autogenerate = AutoGenerateOption.NONE;
|
||||
}
|
||||
String hiddenchunkstyle = worldConfiguration.getString("hidestyle", "stone");
|
||||
if(hiddenchunkstyle.equals("air"))
|
||||
dynmapWorld.hiddenchunkstyle = MapChunkCache.HiddenChunkStyle.FILL_AIR;
|
||||
else if(hiddenchunkstyle.equals("ocean"))
|
||||
dynmapWorld.hiddenchunkstyle = MapChunkCache.HiddenChunkStyle.FILL_OCEAN;
|
||||
else
|
||||
dynmapWorld.hiddenchunkstyle = MapChunkCache.HiddenChunkStyle.FILL_STONE_PLAIN;
|
||||
|
||||
|
||||
// TODO: Make this less... weird...
|
||||
// Insert the world on the same spot as in the configuration.
|
||||
@@ -353,13 +500,11 @@ public class MapManager {
|
||||
public void startRendering() {
|
||||
tileQueue.start();
|
||||
renderpool = new DynmapScheduledThreadPoolExecutor();
|
||||
renderpool.schedule(new DoZoomOutProcessing(), 60000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void stopRendering() {
|
||||
if(renderpool != null) {
|
||||
renderpool.shutdown();
|
||||
renderpool = null;
|
||||
}
|
||||
renderpool.shutdown();
|
||||
tileQueue.stop();
|
||||
}
|
||||
|
||||
@@ -406,22 +551,41 @@ public class MapManager {
|
||||
return world.updates.getUpdatedObjects(since);
|
||||
}
|
||||
|
||||
private static boolean use_legacy = false;
|
||||
/**
|
||||
* Render processor helper - used by code running on render threads to request chunk snapshot cache from server/sync thread
|
||||
*/
|
||||
public MapChunkCache createMapChunkCache(final World w, final DynmapChunk[] chunks) {
|
||||
Callable<MapChunkCache> job = new Callable<MapChunkCache>() {
|
||||
public MapChunkCache call() {
|
||||
return new MapChunkCache(w, chunks);
|
||||
}
|
||||
};
|
||||
Future<MapChunkCache> rslt = scheduler.callSyncMethod(plug_in, job);
|
||||
public MapChunkCache createMapChunkCache(DynmapWorld w, List<DynmapChunk> chunks,
|
||||
boolean blockdata, boolean highesty, boolean biome, boolean rawbiome) {
|
||||
MapChunkCache c = null;
|
||||
try {
|
||||
return rslt.get();
|
||||
} catch (Exception x) {
|
||||
Log.info("createMapChunk - " + x);
|
||||
return null;
|
||||
if(!use_legacy)
|
||||
c = new NewMapChunkCache();
|
||||
} catch (NoClassDefFoundError ncdfe) {
|
||||
use_legacy = true;
|
||||
}
|
||||
if(c == null)
|
||||
c = new LegacyMapChunkCache();
|
||||
if(w.visibility_limits != null) {
|
||||
for(MapChunkCache.VisibilityLimit limit: w.visibility_limits) {
|
||||
c.setVisibleRange(limit);
|
||||
}
|
||||
c.setHiddenFillStyle(w.hiddenchunkstyle);
|
||||
c.setAutoGenerateVisbileRanges(w.do_autogenerate);
|
||||
}
|
||||
c.setChunks(w.world, chunks);
|
||||
if(c.setChunkDataTypes(blockdata, biome, highesty, rawbiome) == false)
|
||||
Log.severe("CraftBukkit build does not support biome APIs");
|
||||
|
||||
synchronized(c) {
|
||||
chunkloads.add(c);
|
||||
try {
|
||||
c.wait();
|
||||
} catch (InterruptedException ix) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
/**
|
||||
* Update map tile statistics
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user