mirror of https://github.com/webbukkit/dynmap.git
Compare commits
445 Commits
Author | SHA1 | Date |
---|---|---|
Michael Primm | b434f09035 | |
Michael Primm | e21198d279 | |
Michael Primm | 1d6346b580 | |
Michael Primm | e086930133 | |
Michael Primm | 27526e64e5 | |
Michael Primm | 21369ec485 | |
Michael Primm | 120889b500 | |
Michael Primm | 669c75322a | |
mikeprimm | ea24554033 | |
JurgenKuyper | b9144e3609 | |
Michael Primm | 9878719337 | |
Michael Primm | 6746631758 | |
Michael Primm | 23cd60ba0a | |
Michael Primm | 328954b256 | |
Michael Primm | 574a400ada | |
Michael Primm | 84ee4cdf0c | |
Michael Primm | dea6a55acd | |
Michael Primm | 87993219bb | |
Michael Primm | 7cdd90768e | |
mikeprimm | b0e56d3e5a | |
Michael Primm | 20700c21b8 | |
Michael Primm | 85885ced0e | |
mikeprimm | 06fbcb8d3d | |
mikeprimm | b181607e5a | |
mikeprimm | bb1438b3c4 | |
ChimneySwift | 1ba6dd4683 | |
ChimneySwift | d16fdc8275 | |
ChimneySwift | 914fc5a10c | |
ChimneySwift | a669d75de0 | |
Jurgen | bc0117ac5a | |
Spongecade | 298b31cdc8 | |
ApliNi | 5244e74d47 | |
JurgenKuyper | 0d15ee5a46 | |
Michael Primm | ca80758605 | |
Michael Primm | 96554717f1 | |
Michael Primm | c807861859 | |
Michael Primm | 65cca049ac | |
JurgenKuyper | 0ba3c8008f | |
Jurgen | 030a0e1d24 | |
Michael Primm | 79f354b111 | |
Michael Primm | 92b9016c65 | |
Michael Primm | e6a18f1029 | |
mikeprimm | ff87b9dd3e | |
Michael Primm | 2d723afba1 | |
Michael Primm | f5d2244450 | |
mikeprimm | e429a53d27 | |
Michael Primm | 169bb81ca7 | |
Michael Primm | 91c4b23a0e | |
Michael Primm | e2a5fc80d3 | |
Michael Primm | 736dd5a290 | |
Michael Primm | 7905f76d51 | |
Murilo Henrique Ghignatti | b97d5045b6 | |
Michael Primm | 85012ae478 | |
Michael Primm | d1408b7bfd | |
Jurgen | c093a95bc0 | |
Michael Primm | 7ed6728e34 | |
Michael Primm | eed1a2b444 | |
mikeprimm | b8b1e8bd4e | |
Michael Primm | ae164f2993 | |
mikeprimm | ebb9dc00d0 | |
mikeprimm | 31d1b400f0 | |
mikeprimm | 105e3887a0 | |
stormboomer | 0120c135c4 | |
stormboomer | b8166a9122 | |
stormboomer | 247e81bc61 | |
James Monger | fe49d37fa9 | |
James Monger | 20592cd805 | |
Michael Primm | b310a57b64 | |
JurgenKuyper | 6b3e18c351 | |
Michael Primm | 105d4f1b62 | |
Thorinwasher | 2503dbfdbb | |
Michael Primm | 87d8c73941 | |
Michael Primm | cee25bc518 | |
Michael Primm | 3715b114e9 | |
Michael Primm | 881b83b7f1 | |
Michael Primm | 7f6dc1d52c | |
mikeprimm | 38ccb50d6a | |
Lewie | fa36d3fa38 | |
mikeprimm | 983fda35b4 | |
Michael Primm | 4e7dcb2cfb | |
Michael Primm | e0c02b1fc0 | |
Michael Primm | b2f04ce112 | |
Michael Primm | 57093caa5f | |
mikeprimm | 551b3adda7 | |
Kosma Moczek | f249ce60b5 | |
Michael Primm | 2f742734d0 | |
Michael Primm | dd81ea2d87 | |
Michael Primm | 126d8e5d05 | |
Michael Primm | 6863243d49 | |
Michael Primm | 43a86b820c | |
Michael Primm | 130953bc12 | |
Michael Primm | 2d835eaeec | |
mikeprimm | 5aeca48e2b | |
Kosma Moczek | 427bd6d0ef | |
Kosma Moczek | 05b751a60e | |
Kosma Moczek | 1450a57aba | |
Kosma Moczek | 0ee1b6001a | |
Kosma Moczek | 1d94af6a11 | |
Kosma Moczek | 8f10ece108 | |
Michael Primm | 2456c36649 | |
Michael Primm | 7bcce9c7e0 | |
Michael Primm | 3f2d9dd5df | |
Michael Primm | 7218e56e5b | |
Michael Primm | 4e61fa6b22 | |
Michael Primm | d1b95c9ae0 | |
Michael Primm | 1ccffb7693 | |
Michael Primm | 5bcfe052a5 | |
Michael Primm | 8b1b26c570 | |
Michael Primm | 022a031829 | |
mikeprimm | 9c0a1e45fc | |
mikeprimm | 3b970c7119 | |
Shaijana | 436dfa22a0 | |
Michael Primm | bcd4ed617a | |
Michael Primm | ab900740b7 | |
Michael Primm | 76649c6250 | |
Michael Primm | 89d06d158d | |
Michael Primm | 2c32cbc0d5 | |
Michael Primm | cc9f6f0bc4 | |
Michael Primm | 8dd9e6eb5a | |
Michael Primm | ea21f4c4df | |
Michael Primm | 485aec3c1c | |
Michael Primm | 0f0d4f2ce9 | |
mikeprimm | 83d9247f78 | |
mikeprimm | bfd43d678c | |
Michael Primm | 9a02868534 | |
Michael Primm | f25d17d3ce | |
mikeprimm | 4a0225bf83 | |
Kosma Moczek | 7af46a04a6 | |
Michael Primm | 2fd5db2835 | |
Michael Primm | caef8f433e | |
mikeprimm | a52ea70b27 | |
Kosma Moczek | b4c4b21a04 | |
Kosma Moczek | 3bb74d41c2 | |
Kosma Moczek | ff5f829f16 | |
Kosma Moczek | eee5565f86 | |
Kosma Moczek | d85be30e43 | |
Kosma Moczek | 098081f2f3 | |
mikeprimm | bb0e9dada7 | |
mikeprimm | fd2e4ba8c8 | |
mikeprimm | c508711f1c | |
Max | 52829462e9 | |
Max | 1a261c6422 | |
Shaijana | bf8a8d9b45 | |
Jurgen | cc88883dc1 | |
Jurgen | 7b82a9182e | |
Michael Primm | 4efc418691 | |
Michael Primm | f773175a7b | |
mikeprimm | dbfcfe03d4 | |
mikeprimm | 322c370bbc | |
mikeprimm | 6fd70b65fe | |
mikeprimm | 202625ac23 | |
JurgenKuyper | 8f62d8e57e | |
Jurgen | d681f05eeb | |
Joo200 | ae9e144774 | |
jonasbn | af930cd9d4 | |
Michael Primm | a6548ec0b7 | |
Michael Primm | 5ddcf1794e | |
Michael Primm | 9f9d12a580 | |
Michael Primm | fe100abb51 | |
Michael Primm | edf6e256e1 | |
Michael Primm | 814068cf53 | |
Michael Primm | 287d900047 | |
mikeprimm | bc7ecb4f23 | |
Joo200 | 0122561150 | |
mikeprimm | e168e87bba | |
mastermc05 | fe4ff57279 | |
Michael Primm | 8af0ad8b8c | |
mikeprimm | 9e58477f3d | |
Kosma Moczek | 7dee2150b6 | |
Kosma Moczek | 7a5440f32e | |
Kosma Moczek | c1fcfd15b6 | |
Kosma Moczek | 743c6ee946 | |
Kosma Moczek | 68a379cdd2 | |
Kosma Moczek | 5795ebeac6 | |
Kosma Moczek | 0f6c2520ff | |
Kosma Moczek | 2ed13761c4 | |
Michael Primm | eca305c519 | |
mikeprimm | d048aad743 | |
mikeprimm | e0cbd1fe8e | |
mikeprimm | e15f3f8460 | |
mikeprimm | 26fa3a24c5 | |
mikeprimm | 7d1a273e6d | |
mikeprimm | 9f16074a75 | |
mikeprimm | 9a8ef557af | |
mikeprimm | 7f71e7ef9b | |
mastermc05 | a5e7ae1013 | |
mastermc05 | e3911b0d3b | |
mastermc05 | adc9e273ca | |
mastermc05 | 4fdb04725d | |
mastermc05 | d434b33cfb | |
mastermc05 | 1f352e0b11 | |
mastermc05 | ed9fb8614d | |
mastermc05 | 9060c8f32b | |
mastermc05 | a6ead1bc3d | |
mastermc05 | 6245a18381 | |
mastermc05 | 0043a1e4fb | |
mastermc05 | ec3c0e998b | |
mastermc05 | c643430225 | |
mastermc05 | 64407e3ce1 | |
mastermc05 | 0f8174796c | |
Captain Chaos | 53b3b7c08b | |
Joseph Gullo | ce54de0cd7 | |
mastermc05 | 0ebbc2bbe5 | |
mastermc05 | a40592021f | |
mastermc05 | 053df84196 | |
mastermc05 | 97a82a3d1b | |
mastermc05 | f34929c6cf | |
mastermc05 | 5f29846645 | |
mastermc05 | 8a8e2ecfcf | |
mastermc05 | 1f1a342777 | |
mastermc05 | 59f44f7425 | |
mastermc05 | 39adaeca56 | |
Warrior | 8ce85322dd | |
Maximilian Zettler | a70530edc8 | |
gmfamily | 61bfe66430 | |
mikeprimm | 66fe5d4a8b | |
mikeprimm | 5aaff7cea9 | |
mikeprimm | 686d61c463 | |
Jurgen | d25040e1cf | |
Jurgen | adfe0471e3 | |
Kosma Moczek | e32b8d0f77 | |
mikeprimm | 5d867239b2 | |
FedUpWith-Tech | aa4d50503e | |
Mike Primm | f96b4d2900 | |
Mike Primm | 2a10499325 | |
Mike Primm | a6b56dc36e | |
Mike Primm | 0445814ef5 | |
Mike Primm | 4cd915e1ab | |
mikeprimm | 171b7c9e54 | |
mikeprimm | 7ddecaa566 | |
mikeprimm | a2c1941585 | |
mikeprimm | b9e57e4e33 | |
Kosma Moczek | 058599be77 | |
mastermc05 | 36924b4942 | |
stepech | 0eb2dffac2 | |
Michele | e2da0efd8e | |
mastermc05 | 36ea4c3938 | |
mastermc05 | d0e9b66d4a | |
Mike Primm | f89777a0dd | |
Mike Primm | 0ab9c9e47b | |
Mike Primm | 3b0814e853 | |
Mike Primm | 46bd040981 | |
Michele0303 | 8909fea4b1 | |
Michele0303 | b5ac020a56 | |
Mike Primm | 7570cf5994 | |
Mike Primm | 85f09b9c2f | |
mikeprimm | fe97e28401 | |
Евгений | 43c1159fae | |
Mike Primm | b331cfaf27 | |
Mike Primm | dc66d12916 | |
Mike Primm | 082878aade | |
Mike Primm | bf8d5eb6cf | |
mikeprimm | 7dabbab8c9 | |
Kosma Moczek | e943a26a5b | |
Kosma Moczek | 1de1c7ce69 | |
Kosma Moczek | 682ed12c69 | |
Kosma Moczek | dc0296f845 | |
Kosma Moczek | 9cd7a3489a | |
Kosma Moczek | 4ec0d5af37 | |
Mike Primm | 47f5779e6f | |
Mike Primm | 937ab7cee7 | |
Mike Primm | a71348c3c8 | |
Mike Primm | 9648457727 | |
Mike Primm | e0619ec650 | |
Mike Primm | 8e27d5defd | |
Mike Primm | d88ebb0d20 | |
Mike Primm | e13a515baf | |
Mike Primm | 8beba92f8e | |
Mike Primm | c80f7adb23 | |
Mike Primm | ab54919956 | |
Mike Primm | e68f628131 | |
Mike Primm | 00a0d3ed37 | |
mikeprimm | fc678a056f | |
mikeprimm | 2d6bcbbca2 | |
mikeprimm | c248ce3275 | |
mikeprimm | 8f70d5fc3c | |
mikeprimm | 4d34510c8b | |
mastermc05 | 075b27a2c4 | |
Mike Primm | 425c870895 | |
Markus Reiter | 8e02c21a36 | |
Markus Reiter | ca5d2f4990 | |
mastermc05 | b933f6b21c | |
mastermc05 | 17e60cff40 | |
mastermc05 | 8d8a4d088e | |
JurgenKuyper | dd789b3a41 | |
Jurgen | a8af8037cb | |
JurgenKuyper | d93a014c99 | |
PssbleTrngle | 3b1cbdca09 | |
PssbleTrngle | c25945ea13 | |
PssbleTrngle | 9f865fa5bd | |
PssbleTrngle | 53f048ac86 | |
Mike Primm | 5818919607 | |
Mike Primm | 69cd5777fc | |
Mike Primm | a119844669 | |
mikeprimm | 5009159fb4 | |
tecdude | 63ab35a9a5 | |
mikeprimm | e7e8f1c245 | |
Mike Primm | 57b48ba56f | |
Mike Primm | 9b7c7aa496 | |
Mike Primm | 9f20e7a174 | |
mikeprimm | 4f1ec1131c | |
Kosma Moczek | a39e00ac0f | |
Mike Primm | 9c9c93493e | |
Leonid Meleshin | f8a81ce0ac | |
Mike Primm | 0592bc9f04 | |
mikeprimm | 85d558d932 | |
mikeprimm | 61a377a3ac | |
mikeprimm | 374309e004 | |
mikeprimm | 6306ae59ea | |
mikeprimm | 79ed487311 | |
Marijn Doeve | 536b96a5f9 | |
RedstoneFuture | 078275d16d | |
Kosma Moczek | 24ecd0f72c | |
Kosma Moczek | f02a73bb0d | |
Kosma Moczek | 556051dc9a | |
Kosma Moczek | f80bb89d96 | |
Kosma Moczek | 4e41f1778b | |
Kosma Moczek | 61b03bcdbb | |
Kosma Moczek | 0ba89fefc4 | |
Kosma Moczek | 16b30ee40f | |
Kosma Moczek | bf4f31c380 | |
Leonid Meleshin | 505d78a8e0 | |
PssbleTrngle | a2951b798d | |
PssbleTrngle | 8763ad91e4 | |
PssbleTrngle | b2a072c45c | |
PssbleTrngle | 5791632d35 | |
Jurgen | b3169a6442 | |
CatMoe | fa6b729b6e | |
mikeprimm | 9c80489ec6 | |
mastermc05 | d4b097ea50 | |
mastermc05 | d0a791b634 | |
mastermc05 | c3214a81bb | |
mastermc05 | da05fc4675 | |
mastermc05 | 790f1f4966 | |
Mike Primm | 75789b29a6 | |
mastermc05 | 4a97550b63 | |
mastermc05 | c5d113b77a | |
mastermc05 | de510108a2 | |
Mike Primm | 7268db3ed2 | |
Mike Primm | 241bc53cb9 | |
Mike Primm | 5a3a216689 | |
mastermc05 | b0f0a4deb5 | |
mikeprimm | c8801dbb8c | |
mikeprimm | 971a492964 | |
Mike Primm | d93b836ad0 | |
Mike Primm | 7feb9e6735 | |
Mike Primm | 861d1f8606 | |
Mike Primm | 93c9ab0b5b | |
Mike Primm | ab76953294 | |
Mike Primm | 53b65ab7e4 | |
Mike Primm | aec1f0cdb6 | |
Mike Primm | 042f387ecf | |
FedUpWith-Tech | 8aa757b049 | |
David Pfeiffer | 8626d0a1cc | |
David Pfeiffer | f52d2e6c1a | |
generrosity | 015309f8ba | |
FedUpWith-Tech | ec6fd59999 | |
FedUpWith-Tech | 04fba09583 | |
Mike Primm | a765f728f1 | |
Mike Primm | d4d60882fc | |
Mike Primm | 7dd55de52e | |
Mike Primm | 98f2057dd0 | |
Mike Primm | 4c2e22e273 | |
Mike Primm | c3d36dfbf2 | |
Mike Primm | a86c8a29e1 | |
mikeprimm | 92af9b5814 | |
Mike Primm | d635473d50 | |
Mike Primm | 19ee08716b | |
generrosity | 1016c7833b | |
Kosma Moczek | fb37658588 | |
Kosma Moczek | 8fee16cd4e | |
Kosma Moczek | 0d7bfc718e | |
Kosma Moczek | 0f482489f7 | |
Kosma Moczek | cb167d9c04 | |
generrosity | e47d6521f4 | |
Mike Primm | ed27140fb5 | |
Mike Primm | 58a2b16217 | |
Mike Primm | cf528d22cc | |
Mike Primm | 9d1b84c9d2 | |
Mike Primm | 3cbd198a2a | |
Mike Primm | 60147e8d16 | |
Mike Primm | a9b4ace851 | |
Mike Primm | 037d1803a7 | |
Mike Primm | 97e5627e0d | |
Mike Primm | f075bf236c | |
Mike Primm | ad226141fe | |
Mike Primm | 6a95c9231a | |
mikeprimm | b6d0c816a4 | |
Mike Primm | 9066fa0135 | |
Mike Primm | 50e6317fa9 | |
Mike Primm | f27fbc9f3e | |
Mike Primm | 1f8bd81894 | |
Mike Primm | 10289f85b7 | |
mikeprimm | d9c5b78dbc | |
Mike Primm | ef045da32f | |
Mike Primm | ea97296684 | |
Mike Primm | 45bc02cf3a | |
Mike Primm | be43f53d81 | |
Mike Primm | 50dce9b854 | |
Alexander Degenhart | ec8d44ea7c | |
Mike Primm | 8eb69514f2 | |
Mike Primm | 474c5ecca9 | |
Mike Primm | a81249539b | |
Mike Primm | ee78384cdc | |
Mike Primm | fb0cceca58 | |
Mike Primm | 3a39688dc8 | |
Mike Primm | 342e67e205 | |
Mike Primm | 15b1328c0e | |
Mike Primm | 04147aadb1 | |
Mike Primm | dacd51aabb | |
Mike Primm | 53c4ebf233 | |
Mike Primm | 19038b3f8b | |
Mike Primm | b43efb1bb6 | |
Mike Primm | d0e627607b | |
Mike Primm | 9126cbf649 | |
Mike Primm | 685b4f9e68 | |
Mike Primm | de79f8e8bc | |
Mike Primm | dc129548aa | |
Mike Primm | 619167c2df | |
Mike Primm | 41b5c6f353 | |
Mike Primm | 069c518a7c | |
Mike Primm | 6e2959a63a | |
Mike Primm | 95c41d91be | |
Mike Primm | b88aa42853 | |
Mike Primm | d941aec6eb | |
Mike Primm | de344869b7 | |
Mike Primm | 93c84ef15e | |
Mike Primm | ff2e1b3b50 | |
Mike Primm | 7121233462 | |
Mike Primm | 8fbc3e3534 | |
Mike Primm | 611832fa22 | |
Mike Primm | a2f8f9defa | |
Mike Primm | b3de1dafe3 | |
Mike Primm | f441cf4ecd | |
Mike Primm | 79f27e9565 | |
Mike Primm | cf5f4a0d9e | |
Mike Primm | 23b33a7828 | |
Mike Primm | 9d89e56586 | |
Mike Primm | d6b1383825 | |
Mike Primm | c83af6dfdc | |
Mike Primm | cfcd8fbf3e | |
Mike Primm | e16b642e0c | |
Mike Primm | 1093da7657 | |
Mike Primm | 0c34d5a5b5 | |
Mike Primm | 6ce6b4a07f |
|
@ -36,6 +36,9 @@ ko
|
|||
patreon
|
||||
README
|
||||
Gradle
|
||||
gradlew
|
||||
gradle
|
||||
oldgradle
|
||||
Curseforge
|
||||
SpigotMC
|
||||
PaperMC
|
||||
|
@ -55,3 +58,4 @@ JDK
|
|||
ForgeGradle
|
||||
Kosma
|
||||
Kosma's
|
||||
DEV
|
||||
|
|
|
@ -11,4 +11,4 @@ jobs:
|
|||
- name: actions/checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: rojopolis/spellcheck - actually doing something
|
||||
uses: rojopolis/spellcheck-github-actions@0.20.0
|
||||
uses: rojopolis/spellcheck-github-actions@0.29.0
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"java.configuration.updateBuildConfiguration": "automatic"
|
||||
"java.configuration.updateBuildConfiguration": "automatic",
|
||||
"java.compile.nullAnalysis.mode": "automatic"
|
||||
}
|
|
@ -1,14 +1,31 @@
|
|||
description = "DynmapCore"
|
||||
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
eclipse {
|
||||
project {
|
||||
name = "Dynmap(DynmapCore)"
|
||||
}
|
||||
}
|
||||
|
||||
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':DynmapCoreAPI', configuration: 'shadow')
|
||||
implementation project(':DynmapCoreAPI')
|
||||
implementation 'javax.servlet:javax.servlet-api:3.1'
|
||||
implementation 'org.eclipse.jetty:jetty-server:9.4.26.v20200117'
|
||||
implementation'org.eclipse.jetty:jetty-server:9.4.26.v20200117'
|
||||
implementation 'org.eclipse.jetty:jetty-servlet:9.4.26.v20200117'
|
||||
implementation 'com.googlecode.json-simple:json-simple:1.1.1'
|
||||
implementation 'org.yaml:snakeyaml:1.23' // DON'T UPDATE - NEWER ONE TRIPS ON WINDOWS ENCODED FILES
|
||||
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20180219.1'
|
||||
implementation 'org.postgresql:postgresql:42.2.18'
|
||||
implementation 'io.github.linktosriram.s3lite:core:0.0.2-SNAPSHOT'
|
||||
implementation 'io.github.linktosriram.s3lite:api:0.0.2-SNAPSHOT'
|
||||
implementation 'io.github.linktosriram.s3lite:http-client-url-connection:0.0.2-SNAPSHOT'
|
||||
implementation 'io.github.linktosriram.s3lite:http-client-spi:0.0.2-SNAPSHOT'
|
||||
implementation 'io.github.linktosriram.s3lite:util:0.0.2-SNAPSHOT'
|
||||
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.1'
|
||||
implementation 'com.sun.xml.bind:jaxb-impl:3.0.0'
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
@ -31,7 +48,7 @@ processResources {
|
|||
}
|
||||
|
||||
jar {
|
||||
classifier = 'unshaded'
|
||||
archiveClassifier = 'unshaded'
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
|
@ -43,6 +60,13 @@ shadowJar {
|
|||
include(dependency('org.eclipse.jetty::'))
|
||||
include(dependency('org.eclipse.jetty.orbit:javax.servlet:'))
|
||||
include(dependency('org.postgresql:postgresql:'))
|
||||
include(dependency('io.github.linktosriram.s3lite:core:'))
|
||||
include(dependency('io.github.linktosriram.s3lite:api:'))
|
||||
include(dependency('io.github.linktosriram.s3lite:http-client-url-connection:'))
|
||||
include(dependency('io.github.linktosriram.s3lite:http-client-spi:'))
|
||||
include(dependency('io.github.linktosriram.s3lite:util:'))
|
||||
include(dependency('jakarta.xml.bind::'))
|
||||
include(dependency('com.sun.xml.bind::'))
|
||||
include(dependency(':DynmapCoreAPI'))
|
||||
exclude("META-INF/maven/**")
|
||||
exclude("META-INF/services/**")
|
||||
|
@ -53,8 +77,10 @@ shadowJar {
|
|||
relocate('org.owasp.html', 'org.dynmap.org.owasp.html')
|
||||
relocate('javax.servlet', 'org.dynmap.javax.servlet' )
|
||||
relocate('org.postgresql', 'org.dynmap.org.postgresql')
|
||||
destinationDir = file '../target'
|
||||
classifier = ''
|
||||
relocate('io.github.linktosriram.s3lite', 'org.dynmap.s3lite')
|
||||
|
||||
destinationDirectory = file '../target'
|
||||
archiveClassifier = ''
|
||||
}
|
||||
|
||||
artifacts {
|
||||
|
|
|
@ -4,8 +4,6 @@ import java.io.IOException;
|
|||
import java.io.Writer;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.sound.sampled.AudioFormat.Encoding;
|
||||
|
||||
import org.json.simple.JSONAware;
|
||||
import org.json.simple.JSONStreamAware;
|
||||
import org.owasp.html.HtmlPolicyBuilder;
|
||||
|
@ -288,6 +286,8 @@ public class Client {
|
|||
private static PolicyFactory sanitizer = null;
|
||||
private static PolicyFactory OLDTAGS = new HtmlPolicyBuilder().allowElements("center", "basefont", "hr").toFactory();
|
||||
public static String sanitizeHTML(String html) {
|
||||
// Don't sanitize if null or no html markup
|
||||
if ((html == null) || (html.indexOf('<') < 0)) return html;
|
||||
PolicyFactory s = sanitizer;
|
||||
if (s == null) {
|
||||
// Generous but safe html formatting allowances
|
||||
|
|
|
@ -12,6 +12,7 @@ public class ClientUpdateComponent extends Component {
|
|||
private int hideifshadow;
|
||||
private int hideifunder;
|
||||
private boolean hideifsneaking;
|
||||
private boolean hideifspectator;
|
||||
private boolean hideifinvisiblepotion;
|
||||
private boolean is_protected;
|
||||
public static boolean usePlayerColors;
|
||||
|
@ -24,6 +25,7 @@ public class ClientUpdateComponent extends Component {
|
|||
hideifshadow = configuration.getInteger("hideifshadow", 15);
|
||||
hideifunder = configuration.getInteger("hideifundercover", 15);
|
||||
hideifsneaking = configuration.getBoolean("hideifsneaking", false);
|
||||
hideifspectator = configuration.getBoolean("hideifspectator", false);
|
||||
hideifinvisiblepotion = configuration.getBoolean("hide-if-invisiblity-potion", true);
|
||||
is_protected = configuration.getBoolean("protected-player-info", false);
|
||||
usePlayerColors = configuration.getBoolean("use-name-colors", false);
|
||||
|
@ -100,6 +102,9 @@ public class ClientUpdateComponent extends Component {
|
|||
if((!hide) && hideifsneaking && p.isSneaking()) {
|
||||
hide = true;
|
||||
}
|
||||
if((!hide) && hideifspectator && p.isSpectator()) {
|
||||
hide = true;
|
||||
}
|
||||
if((!hide) && is_protected && (!see_all)) {
|
||||
if(e.user != null) {
|
||||
hide = !core.testIfPlayerVisibleToPlayer(e.user, p.getName());
|
||||
|
|
|
@ -105,7 +105,6 @@ public class ColorScheme {
|
|||
continue;
|
||||
}
|
||||
Integer id = null;
|
||||
Integer dat = null;
|
||||
boolean isbiome = false;
|
||||
boolean istemp = false;
|
||||
boolean israin = false;
|
||||
|
@ -129,7 +128,7 @@ public class ColorScheme {
|
|||
id = -1;
|
||||
BiomeMap[] bm = BiomeMap.values();
|
||||
for (int i = 0; i < bm.length; i++) {
|
||||
if (bm[i].toString().equalsIgnoreCase(bio)) {
|
||||
if (bm[i].getId().equalsIgnoreCase(bio)) {
|
||||
id = i;
|
||||
break;
|
||||
} else if (bio.equalsIgnoreCase("BIOME_" + i)) {
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package org.dynmap;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -82,13 +86,13 @@ public class ConfigurationNode implements Map<String, Object> {
|
|||
initparse();
|
||||
// If no file to read, just return false
|
||||
if (!f.canRead()) { return false; }
|
||||
FileInputStream fis = null;
|
||||
Reader fr = null;
|
||||
try {
|
||||
fis = new FileInputStream(f);
|
||||
Object o = yaml.load(new UnicodeReader(fis));
|
||||
fr = new UnicodeReader(new BufferedInputStream(new FileInputStream(f)));
|
||||
Object o = yaml.load(fr);
|
||||
if((o != null) && (o instanceof Map))
|
||||
entries = (Map<String, Object>)o;
|
||||
fis.close();
|
||||
fr.close();
|
||||
}
|
||||
catch (YAMLException e) {
|
||||
Log.severe("Error parsing " + f.getPath() + ". Use http://yamllint.com to debug the YAML syntax." );
|
||||
|
@ -97,8 +101,8 @@ public class ConfigurationNode implements Map<String, Object> {
|
|||
Log.severe("Error reading " + f.getPath());
|
||||
return false;
|
||||
} finally {
|
||||
if(fis != null) {
|
||||
try { fis.close(); } catch (IOException x) {}
|
||||
if(fr != null) {
|
||||
try { fr.close(); } catch (IOException x) {}
|
||||
}
|
||||
}
|
||||
return (entries != null);
|
||||
|
@ -111,7 +115,7 @@ public class ConfigurationNode implements Map<String, Object> {
|
|||
public boolean save(File file) {
|
||||
initparse();
|
||||
|
||||
FileOutputStream stream = null;
|
||||
OutputStream stream = null;
|
||||
|
||||
File parent = file.getParentFile();
|
||||
|
||||
|
@ -120,7 +124,7 @@ public class ConfigurationNode implements Map<String, Object> {
|
|||
}
|
||||
|
||||
try {
|
||||
stream = new FileOutputStream(file);
|
||||
stream = new BufferedOutputStream(new FileOutputStream(file));
|
||||
OutputStreamWriter writer = new OutputStreamWriter(stream, "UTF-8");
|
||||
yaml.dump(entries, writer);
|
||||
return true;
|
||||
|
|
|
@ -54,12 +54,15 @@ import org.dynmap.modsupport.ModSupportImpl;
|
|||
import org.dynmap.renderer.DynmapBlockState;
|
||||
import org.dynmap.servlet.*;
|
||||
import org.dynmap.storage.MapStorage;
|
||||
import org.dynmap.storage.aws_s3.AWSS3MapStorage;
|
||||
import org.dynmap.storage.filetree.FileTreeMapStorage;
|
||||
import org.dynmap.storage.mysql.MySQLMapStorage;
|
||||
import org.dynmap.storage.mssql.MicrosoftSQLMapStorage;
|
||||
import org.dynmap.storage.mariadb.MariaDBMapStorage;
|
||||
import org.dynmap.storage.sqllte.SQLiteMapStorage;
|
||||
import org.dynmap.storage.postgresql.PostgreSQLMapStorage;
|
||||
import org.dynmap.utils.BlockStep;
|
||||
import org.dynmap.utils.BufferOutputStream;
|
||||
import org.dynmap.utils.ImageIOManager;
|
||||
import org.dynmap.web.BanIPFilter;
|
||||
import org.dynmap.web.CustomHeaderFilter;
|
||||
|
@ -75,7 +78,6 @@ import org.eclipse.jetty.server.handler.HandlerList;
|
|||
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.resource.FileResource;
|
||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
|
@ -132,6 +134,8 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
private int config_hashcode; /* Used to signal need to reload web configuration (world changes, config update, etc) */
|
||||
private int fullrenderplayerlimit; /* Number of online players that will cause fullrender processing to pause */
|
||||
private int updateplayerlimit; /* Number of online players that will cause update processing to pause */
|
||||
private String publicURL; // If set, public HRL for accessing dynmap (declared by administrator)
|
||||
private String noPermissionMsg;
|
||||
private boolean didfullpause;
|
||||
private boolean didupdatepause;
|
||||
private Map<String, LinkedList<String>> ids_by_ip = new HashMap<String, LinkedList<String>>();
|
||||
|
@ -160,6 +164,7 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
private File dataDirectory;
|
||||
private File tilesDirectory;
|
||||
private File exportDirectory;
|
||||
private File importDirectory;
|
||||
private String plugin_ver;
|
||||
private MapStorage defaultStorage;
|
||||
|
||||
|
@ -173,6 +178,8 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
private Boolean webserverCompConfigWarn = false;
|
||||
private final String CompConfigWiki = "https://github.com/webbukkit/dynmap/wiki/Component-Configuration";
|
||||
|
||||
private final String[] defaultTemplates = {"vlowres", "lowres", "medres", "hires", "low_boost_hi",
|
||||
"hi_boost_vhi", "hi_boost_xhi"};
|
||||
/* Constructor for core */
|
||||
public DynmapCore() {
|
||||
}
|
||||
|
@ -218,6 +225,9 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
public final File getExportFolder() {
|
||||
return exportDirectory;
|
||||
}
|
||||
public final File getImportFolder() {
|
||||
return importDirectory;
|
||||
}
|
||||
public void setMinecraftVersion(String mcver) {
|
||||
this.platformVersion = mcver;
|
||||
}
|
||||
|
@ -422,6 +432,11 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
if (!exportDirectory.isDirectory() && !exportDirectory.mkdirs()) {
|
||||
Log.warning("Could not create directory for exports ('" + exportDirectory + "').");
|
||||
}
|
||||
// Prime the imports directory
|
||||
importDirectory = getFile(configuration.getString("importpath", "import"));
|
||||
if (!importDirectory.isDirectory() && !importDirectory.mkdirs()) {
|
||||
Log.warning("Could not create directory for imports ('" + importDirectory + "').");
|
||||
}
|
||||
// Create default storage handler
|
||||
String storetype = configuration.getString("storage/type", "filetree");
|
||||
if (storetype.equals("filetree")) {
|
||||
|
@ -439,6 +454,12 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
else if (storetype.equals("postgres") || storetype.equals("postgresql")) {
|
||||
defaultStorage = new PostgreSQLMapStorage();
|
||||
}
|
||||
else if (storetype.equals("aws_s3")) {
|
||||
defaultStorage = new AWSS3MapStorage();
|
||||
}
|
||||
else if (storetype.equals("microsoftsql")) {
|
||||
defaultStorage = new MicrosoftSQLMapStorage();
|
||||
}
|
||||
else {
|
||||
Log.severe("Invalid storage type for map data: " + storetype);
|
||||
return false;
|
||||
|
@ -486,7 +507,10 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
authmgr = new WebAuthManager(this);
|
||||
defaultStorage.setLoginEnabled(this);
|
||||
}
|
||||
|
||||
// If storage serves web files, extract and publsh them
|
||||
if (defaultStorage.needsStaticWebFiles()) {
|
||||
updateStaticWebToStorage();
|
||||
}
|
||||
/* Load control for leaf transparency (spout lighting bug workaround) */
|
||||
transparentLeaves = configuration.getBoolean("transparent-leaves", true);
|
||||
|
||||
|
@ -558,6 +582,11 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
if (migrate_chunks)
|
||||
Log.info("EXPERIMENTAL: chunk migration enabled");
|
||||
|
||||
publicURL = configuration.getString("publicURL", "");
|
||||
|
||||
/* Send this message if the player does not have permission to use the command */
|
||||
noPermissionMsg = configuration.getString("noPermissionMsg", "You don't have permission to use this command!");
|
||||
|
||||
/* Load preupdate/postupdate commands */
|
||||
ImageIOManager.preUpdateCommand = configuration.getString("custom-commands/image-updates/preupdatecommand", "");
|
||||
ImageIOManager.postUpdateCommand = configuration.getString("custom-commands/image-updates/postupdatecommand", "");
|
||||
|
@ -683,7 +712,7 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
/* Print version info */
|
||||
Log.info("version " + plugin_ver + " is enabled - core version " + version );
|
||||
Log.info("For support, visit our Discord at https://discord.gg/s3rd5qn");
|
||||
Log.info("For news, visit https://reddit.com/r/Dynmap or follow https://twitter.com/Dynmap");
|
||||
Log.info("For news, visit https://reddit.com/r/Dynmap or follow https://universeodon.com/@dynmap");
|
||||
Log.info("To report or track bugs, visit https://github.com/webbukkit/dynmap/issues");
|
||||
Log.info("If you'd like to donate, please visit https://www.patreon.com/dynmap or https://ko-fi.com/michaelprimm");
|
||||
|
||||
|
@ -913,12 +942,13 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
return config_hashcode;
|
||||
}
|
||||
|
||||
private FileResource createFileResource(String path) {
|
||||
@SuppressWarnings("deprecation")
|
||||
private org.eclipse.jetty.util.resource.FileResource createFileResource(String path) {
|
||||
try {
|
||||
File f = new File(path);
|
||||
URI uri = f.toURI();
|
||||
URL url = uri.toURL();
|
||||
return new FileResource(url);
|
||||
return new org.eclipse.jetty.util.resource.FileResource(url);
|
||||
} catch(Exception e) {
|
||||
Log.info("Could not create file resource");
|
||||
return null;
|
||||
|
@ -1094,7 +1124,9 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
mapManager.stopRendering();
|
||||
mapManager = null;
|
||||
}
|
||||
|
||||
if (defaultStorage != null) {
|
||||
defaultStorage.shutdownStorage();
|
||||
}
|
||||
playerfacemgr = null;
|
||||
/* Clean up registered listeners */
|
||||
listenerManager.cleanup();
|
||||
|
@ -1210,6 +1242,7 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
"del-id-for-ip",
|
||||
"webregister",
|
||||
"dumpmemory",
|
||||
"url",
|
||||
"help"}));
|
||||
|
||||
private static class CommandInfo {
|
||||
|
@ -1277,6 +1310,7 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
new CommandInfo("dynmap", "webregister", "<player>", "Start registration process for creating web login account for player <player>"),
|
||||
new CommandInfo("dynmap", "version", "Return version information"),
|
||||
new CommandInfo("dynmap", "dumpmemory", "Return mempry use information"),
|
||||
new CommandInfo("dynmap", "url", "Return confgured URL for Dynmap web"),
|
||||
new CommandInfo("dmarker", "", "Manipulate map markers."),
|
||||
new CommandInfo("dmarker", "add", "<label>", "Add new marker with label <label> at current location (use double-quotes if spaces needed)."),
|
||||
new CommandInfo("dmarker", "add", "id:<id> <label>", "Add new marker with ID <id> at current location (use double-quotes if spaces needed)."),
|
||||
|
@ -1334,7 +1368,7 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
new CommandInfo("dmap", "mapadd", "<world>:<map> <attrib>:<value> <attrib>:<value>", "Create map for world <world> with name <map> using provided attributes."),
|
||||
new CommandInfo("dmap", "mapset", "<world>:<map> <attrib>:<value> <attrib>:<value>", "Update map <map> of world <world> with new attribute values."),
|
||||
new CommandInfo("dmap", "worldreset", "<world>", "Reset world <world> to default template for world type"),
|
||||
new CommandInfo("dmap", "worldreset", "<world> <templatename>", "Reset world <world> to temaplte <templatename>."),
|
||||
new CommandInfo("dmap", "worldreset", "<world> <templatename>", "Reset world <world> to template <templatename>."),
|
||||
new CommandInfo("dmap", "worldgetlimits", "<world>", "List visibity and hidden limits for world"),
|
||||
new CommandInfo("dmap", "worldaddlimit", "<world> corner1:<x>/<z> corner2:<x>/<z>", "Add rectangular visibilty limit"),
|
||||
new CommandInfo("dmap", "worldaddlimit", "<world> type:round center:<x>/<z> radius:<radius>", "Add round visibilty limit"),
|
||||
|
@ -1584,7 +1618,7 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
printCommandHelp(sender, cmd, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (c.equals("render") && checkPlayerPermission(sender,"render")) {
|
||||
if (player != null) {
|
||||
DynmapLocation loc = player.getLocation();
|
||||
|
@ -1907,12 +1941,20 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
else if(c.equals("help")) {
|
||||
printCommandHelp(sender, cmd, (args.length > 1)?args[1]:"");
|
||||
}
|
||||
else if(c.equals("dumpmemory")) {
|
||||
else if(c.equals("dumpmemory") && checkPlayerPermission(sender, "dumpmemory")) {
|
||||
TexturePack.tallyMemory(sender);
|
||||
}
|
||||
else if(c.equals("version")) {
|
||||
sender.sendMessage("Dynmap version: core=" + this.getDynmapCoreVersion() + ", plugin=" + this.getDynmapPluginVersion());
|
||||
}
|
||||
else if (c.equals("url")) {
|
||||
if (publicURL.length() > 0) {
|
||||
sender.sendMessage("Dynmap URL for this server is: " + publicURL);
|
||||
}
|
||||
else {
|
||||
sender.sendMessage("URL of Dynmap not configured");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
printCommandHelp(sender, cmd, (args.length > 0)?args[0]:"");
|
||||
|
@ -1970,11 +2012,11 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
if(args.length == 2) { // /dynmap radiusrender *<world>* <x> <z> <radius> <map>
|
||||
return getWorldSuggestions(args[1]);
|
||||
} if(args.length == 3 && player != null) { // /dynmap radiusrender <radius> *<mapname>*
|
||||
Scanner sc = new Scanner(args[1]);
|
||||
|
||||
if(sc.hasNextInt(10)) { //Only show map suggestions if a number was entered before
|
||||
return getMapSuggestions(player.getLocation().world, args[2], false);
|
||||
}
|
||||
try (Scanner sc = new Scanner(args[1])) {
|
||||
if(sc.hasNextInt(10)) { //Only show map suggestions if a number was entered before
|
||||
return getMapSuggestions(player.getLocation().world, args[2], false);
|
||||
}
|
||||
}
|
||||
} else if(args.length == 6) { // /dynmap radiusrender <world> <x> <z> <radius> *<map>*
|
||||
return getMapSuggestions(args[1], args[5], false);
|
||||
}
|
||||
|
@ -2072,7 +2114,7 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
if (!(sender instanceof DynmapPlayer) || sender.isOp()) {
|
||||
return true;
|
||||
} else if (!sender.hasPrivilege(permission.toLowerCase())) {
|
||||
sender.sendMessage("You don't have permission to use this command!");
|
||||
sender.sendMessage(noPermissionMsg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -2136,6 +2178,9 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
ConfigurationNode getDefaultTemplateConfigurationNode(DynmapWorld world) {
|
||||
String environmentName = world.getEnvironment();
|
||||
if(deftemplatesuffix.length() > 0) {
|
||||
if(!Arrays.asList(defaultTemplates).contains(deftemplatesuffix)) {
|
||||
Log.warning("Not using a default defined template, worlds might not be accessible.");
|
||||
}
|
||||
environmentName += "-" + deftemplatesuffix;
|
||||
}
|
||||
Log.verboseinfo("Using environment as template: " + environmentName);
|
||||
|
@ -2644,7 +2689,6 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
int off = 0;
|
||||
int firsthit = -1;
|
||||
boolean done = false;
|
||||
String orig = msg;
|
||||
while (!done) {
|
||||
int idx = msg.indexOf("${", off); // Look for next ${
|
||||
if (idx >= 0) { // Hit
|
||||
|
@ -2790,7 +2834,7 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
return platformVersion;
|
||||
}
|
||||
|
||||
private static boolean deleteDirectory(File dir) {
|
||||
public static boolean deleteDirectory(File dir) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
|
@ -2805,6 +2849,63 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
}
|
||||
return dir.delete();
|
||||
}
|
||||
private void updateStaticWebToStorage() {
|
||||
if(jarfile == null) return;
|
||||
// If doing update and web path update is disabled, send warning
|
||||
if (!this.updatewebpathfiles) {
|
||||
return;
|
||||
}
|
||||
Log.info("Publishing web files to storage");
|
||||
/* Open JAR as ZIP */
|
||||
ZipFile zf = null;
|
||||
InputStream ins = null;
|
||||
byte[] buf = new byte[2048];
|
||||
String n = null;
|
||||
try {
|
||||
zf = new ZipFile(jarfile);
|
||||
Enumeration<? extends ZipEntry> e = zf.entries();
|
||||
while (e.hasMoreElements()) {
|
||||
ZipEntry ze = e.nextElement();
|
||||
n = ze.getName();
|
||||
if (!n.startsWith("extracted/web/")) {
|
||||
continue;
|
||||
}
|
||||
n = n.substring("extracted/web/".length());
|
||||
// If file is going to web path, redirect it to the configured web
|
||||
if (ze.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
ins = zf.getInputStream(ze);
|
||||
BufferOutputStream buffer = new BufferOutputStream();
|
||||
int len;
|
||||
while ((len = ins.read(buf)) >= 0) {
|
||||
buffer.write(buf, 0, len);
|
||||
}
|
||||
defaultStorage.setStaticWebFile(n, buffer);
|
||||
} catch(IOException io) {
|
||||
Log.severe("Error updating file in storage - " + n, io);
|
||||
} finally {
|
||||
if (ins != null) {
|
||||
ins.close();
|
||||
ins = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException iox) {
|
||||
Log.severe("Error extracting file - " + n);
|
||||
} finally {
|
||||
if (ins != null) {
|
||||
try { ins.close(); } catch (IOException iox) {}
|
||||
ins = null;
|
||||
}
|
||||
if (zf != null) {
|
||||
try { zf.close(); } catch (IOException iox) {}
|
||||
zf = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateExtractedFiles() {
|
||||
if(jarfile == null) return;
|
||||
File df = this.getDataFolder();
|
||||
|
@ -2906,13 +3007,13 @@ public class DynmapCore implements DynmapCommonAPI {
|
|||
}
|
||||
else {
|
||||
try {
|
||||
f.getParentFile().mkdirs();
|
||||
fos = new FileOutputStream(f);
|
||||
ins = zf.getInputStream(ze);
|
||||
int len;
|
||||
while ((len = ins.read(buf)) >= 0) {
|
||||
fos.write(buf, 0, len);
|
||||
}
|
||||
f.getParentFile().mkdirs();
|
||||
fos = new FileOutputStream(f);
|
||||
ins = zf.getInputStream(ze);
|
||||
int len;
|
||||
while ((len = ins.read(buf)) >= 0) {
|
||||
fos.write(buf, 0, len);
|
||||
}
|
||||
} catch(IOException io) {
|
||||
Log.severe("Error updating file - " + f.getPath(), io);
|
||||
} finally {
|
||||
|
|
|
@ -90,7 +90,9 @@ public class DynmapMapCommands {
|
|||
mapSetArgs.put("mapzoomin", emptySupplier);
|
||||
mapSetArgs.put("mapzoomout", emptySupplier);
|
||||
mapSetArgs.put("boostzoom", emptySupplier);
|
||||
mapSetArgs.put("tilescale", emptySupplier);
|
||||
mapSetArgs.put("tileupdatedelay", emptySupplier);
|
||||
mapSetArgs.put("readonly", booleanSupplier);
|
||||
|
||||
tabCompletions = new HashMap<>();
|
||||
tabCompletions.put("worldaddlimit", worldAddLimitArgs);
|
||||
|
@ -695,7 +697,7 @@ public class DynmapMapCommands {
|
|||
sb.append(", lighting=").append(hdmt.getLighting().getName()).append(", mapzoomin=").append(hdmt.getMapZoomIn()).append(", mapzoomout=").append(hdmt.getMapZoomOutLevels());
|
||||
sb.append(", img-format=").append(hdmt.getImageFormatSetting()).append(", icon=").append(hdmt.getIcon());
|
||||
sb.append(", append-to-world=").append(hdmt.getAppendToWorld()).append(", boostzoom=").append(hdmt.getBoostZoom());
|
||||
sb.append(", protected=").append(hdmt.isProtected());
|
||||
sb.append(", protected=").append(hdmt.isProtected()).append(", tilescale=").append(hdmt.getTileScale()).append(", readonly=").append(hdmt.isReadOnly());
|
||||
if(hdmt.tileupdatedelay > 0) {
|
||||
sb.append(", tileupdatedelay=").append(hdmt.tileupdatedelay);
|
||||
}
|
||||
|
@ -913,6 +915,18 @@ public class DynmapMapCommands {
|
|||
}
|
||||
did_update |= mt.setBoostZoom(mzi);
|
||||
}
|
||||
else if(tok[0].equalsIgnoreCase("tilescale")) {
|
||||
int mzi = -1;
|
||||
try {
|
||||
mzi = Integer.valueOf(tok[1]);
|
||||
} catch (NumberFormatException nfx) {
|
||||
}
|
||||
if((mzi < 0) || (mzi > 4)) {
|
||||
sender.sendMessage("Invalid tilescale value: " + tok[1]);
|
||||
return true;
|
||||
}
|
||||
did_update |= mt.setTileScale(mzi);
|
||||
}
|
||||
else if(tok[0].equalsIgnoreCase("tileupdatedelay")) {
|
||||
int tud = -1;
|
||||
try {
|
||||
|
@ -983,6 +997,9 @@ public class DynmapMapCommands {
|
|||
else if(tok[0].equalsIgnoreCase("protected")) {
|
||||
did_update |= mt.setProtected(Boolean.parseBoolean(tok[1]));
|
||||
}
|
||||
else if(tok[0].equalsIgnoreCase("readonly")) {
|
||||
did_update |= mt.setReadOnly(Boolean.parseBoolean(tok[1]));
|
||||
}
|
||||
}
|
||||
if(did_update) {
|
||||
if(core.updateWorldConfig(w)) {
|
||||
|
|
|
@ -136,7 +136,7 @@ public abstract class DynmapWorld {
|
|||
long mostRecentTimestamp = 0;
|
||||
int step = 1 << tile.zoom;
|
||||
MapStorageTile ztile = tile.getZoomOutTile();
|
||||
int width = 128, height = 128;
|
||||
int width = mts.tileSize, height = mts.tileSize;
|
||||
BufferedImage zIm = null;
|
||||
DynmapBufferedImage kzIm = null;
|
||||
boolean blank = true;
|
||||
|
@ -178,7 +178,7 @@ public abstract class DynmapWorld {
|
|||
if ((iwidth == width) && (iheight == height)) {
|
||||
im.getRGB(0, 0, width, height, argb, 0, width); /* Read data */
|
||||
im.flush();
|
||||
/* Do binlinear scale to 64x64 */
|
||||
/* Do binlinear scale to width/2 x height/2 */
|
||||
int off = 0;
|
||||
for(int y = 0; y < height; y += 2) {
|
||||
off = y*width;
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
import org.dynmap.servlet.ClientUpdateServlet;
|
||||
import org.dynmap.servlet.SendMessageServlet;
|
||||
import org.dynmap.utils.IpAddressMatcher;
|
||||
import org.json.simple.JSONObject;
|
||||
import static org.dynmap.JSONUtils.*;
|
||||
|
||||
|
@ -65,12 +66,12 @@ public class InternalClientUpdateComponent extends ClientUpdateComponent {
|
|||
this.core = dcore;
|
||||
if(trustedproxy != null) {
|
||||
for(String s : trustedproxy) {
|
||||
this.proxyaddress.add(s.trim());
|
||||
this.proxyaddress.add(new IpAddressMatcher(s.trim()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.proxyaddress.add("127.0.0.1");
|
||||
this.proxyaddress.add("0:0:0:0:0:0:0:1");
|
||||
this.proxyaddress.add(new IpAddressMatcher("127.0.0.1"));
|
||||
this.proxyaddress.add(new IpAddressMatcher("0:0:0:0:0:0:0:1"));
|
||||
}
|
||||
onMessageReceived.addListener(new Event.Listener<Message> () {
|
||||
@Override
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.json.simple.parser.ParseException;
|
|||
import static org.dynmap.JSONUtils.*;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
|
||||
protected long jsonInterval;
|
||||
|
@ -272,21 +273,28 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
|
|||
byte[] outputBytes = sb.toString().getBytes(cs_utf8);
|
||||
MapManager.scheduleDelayedJob(new Runnable() {
|
||||
public void run() {
|
||||
File f = new File(baseStandaloneDir, "config.js");
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(f);
|
||||
fos.write(outputBytes);
|
||||
} catch (IOException iox) {
|
||||
Log.severe("Exception while writing " + f.getPath(), iox);
|
||||
} finally {
|
||||
if(fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException x) {}
|
||||
fos = null;
|
||||
}
|
||||
}
|
||||
if (core.getDefaultMapStorage().needsStaticWebFiles()) {
|
||||
BufferOutputStream os = new BufferOutputStream();
|
||||
os.write(outputBytes);
|
||||
core.getDefaultMapStorage().setStaticWebFile("standalone/config.js", os);
|
||||
}
|
||||
else {
|
||||
File f = new File(baseStandaloneDir, "config.js");
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(f);
|
||||
fos.write(outputBytes);
|
||||
} catch (IOException iox) {
|
||||
Log.severe("Exception while writing " + f.getPath(), iox);
|
||||
} finally {
|
||||
if(fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException x) {}
|
||||
fos = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
@ -331,9 +339,12 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
|
|||
else {
|
||||
outputFile = "dynmap_" + dynmapWorld.getName() + ".json";
|
||||
}
|
||||
byte[] content = Json.stringifyJson(update).getBytes(cs_utf8);
|
||||
|
||||
enqueueFileWrite(outputFile, content, dowrap);
|
||||
CompletableFuture.runAsync(() -> {
|
||||
byte[] content = Json.stringifyJson(update).getBytes(cs_utf8);
|
||||
|
||||
enqueueFileWrite(outputFile, content, dowrap);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,8 +488,10 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
|
|||
jsonMsgs = (JSONArray) parser.parse(inputFileReader);
|
||||
} catch (IOException ex) {
|
||||
Log.severe("Exception while reading JSON-file.", ex);
|
||||
storage.setStandaloneFile("dynmap_webchat.json", null); // Delete it
|
||||
} catch (ParseException ex) {
|
||||
Log.severe("Exception while parsing JSON-file.", ex);
|
||||
storage.setStandaloneFile("dynmap_webchat.json", null); // Delete it
|
||||
} finally {
|
||||
if(inputFileReader != null) {
|
||||
try {
|
||||
|
|
|
@ -60,6 +60,7 @@ public class MapManager {
|
|||
private int progressinterval = 100;
|
||||
private int tileupdatedelay = 30;
|
||||
private int savependingperiod = 15 * 60; // every 15 minutes, by default
|
||||
private int defaulttilescale = 0;
|
||||
private boolean saverestorepending = true;
|
||||
private boolean pauseupdaterenders = false;
|
||||
private boolean hideores = false;
|
||||
|
@ -190,6 +191,10 @@ public class MapManager {
|
|||
return tileupdatedelay;
|
||||
}
|
||||
|
||||
public int getDefaultTileScale() {
|
||||
return defaulttilescale;
|
||||
}
|
||||
|
||||
private static class OurThreadFactory implements ThreadFactory {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
|
@ -228,8 +233,10 @@ public class MapManager {
|
|||
try {
|
||||
r.run();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Exception during render job: " + r);
|
||||
x.printStackTrace();
|
||||
if (!(x instanceof InterruptedException)) { // Avoid shutdown noise
|
||||
Log.severe("Exception during render job: " + r);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -244,8 +251,10 @@ public class MapManager {
|
|||
try {
|
||||
command.run();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Exception during render job: " + command);
|
||||
x.printStackTrace();
|
||||
if (!(x instanceof InterruptedException)) { // Avoid shutdown noise
|
||||
Log.severe("Exception during render job: " + command);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, delay, unit);
|
||||
|
@ -284,6 +293,7 @@ public class MapManager {
|
|||
boolean pausedforworld = false;
|
||||
boolean updaterender = false;
|
||||
boolean resume = false;
|
||||
boolean resumeInitDone = false;
|
||||
boolean quiet = false;
|
||||
String mapname;
|
||||
AtomicLong total_render_ns = new AtomicLong(0L);
|
||||
|
@ -302,32 +312,6 @@ public class MapManager {
|
|||
rendertype = RENDERTYPE_FULLRENDER;
|
||||
}
|
||||
this.resume = resume;
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
if (resume) { // if resume render
|
||||
final MapStorage ms = world.getMapStorage();
|
||||
ms.enumMapBaseTiles(world, map, new MapStorageBaseTileEnumCB() {
|
||||
@Override
|
||||
public void tileFound(MapStorageTile tile, MapType.ImageEncoding enc) {
|
||||
String tileId = String.format("%s_%s_%d_%d", tile.world.getName(), tile.map.getName(), tile.x, tile.y);
|
||||
//sender.sendMessage("Tile found: " + tileId);
|
||||
storedTileIds.add(tileId);
|
||||
}
|
||||
}, new MapStorageTileSearchEndCB() {
|
||||
@Override
|
||||
public void searchEnded() {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
latch.await(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
sender.sendMessage(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Full world, all maps render, with optional render radius */
|
||||
|
@ -519,6 +503,27 @@ public class MapManager {
|
|||
}
|
||||
return;
|
||||
}
|
||||
// If doing resume, load existing tile IDs here (constructor was stupid, and caused timeouts for non-trivial maps - need to check PRs better....
|
||||
if (resume && (!resumeInitDone)) { // if resume render AND init not completed
|
||||
sendMessage(String.format("Scanning map to find existing tiles for resume..."));
|
||||
final MapStorage ms = world.getMapStorage();
|
||||
ms.enumMapBaseTiles(world, map, new MapStorageBaseTileEnumCB() {
|
||||
@Override
|
||||
public void tileFound(MapStorageTile tile, MapType.ImageEncoding enc) {
|
||||
String tileId = String.format("%s_%s_%d_%d", tile.world.getName(), tile.map.getName(), tile.x, tile.y);
|
||||
//sender.sendMessage("Tile found: " + tileId);
|
||||
storedTileIds.add(tileId);
|
||||
}
|
||||
}, new MapStorageTileSearchEndCB() {
|
||||
@Override
|
||||
public void searchEnded() {
|
||||
|
||||
}
|
||||
});
|
||||
sendMessage(String.format("Scan complete - starting render"));
|
||||
resumeInitDone = true; // Only due on first run
|
||||
}
|
||||
|
||||
if(tile0 == null) { /* Not single tile render */
|
||||
if (saverestorepending && world.isLoaded() && (savependingperiod > 0) && ((lastPendingSaveTS + (1000 *savependingperiod)) < System.currentTimeMillis())) {
|
||||
savePending(this.world, true); // Save the pending data for the given world
|
||||
|
@ -624,10 +629,12 @@ public class MapManager {
|
|||
renderedmaps.addAll(map.getMapsSharingRender(world));
|
||||
|
||||
/* Now, prime the render queue */
|
||||
for (MapTile mt : map.getTiles(world, (int)loc.x, (int)loc.y, (int)loc.z)) {
|
||||
if (!found.getFlag(mt.tileOrdinalX(), mt.tileOrdinalY())) {
|
||||
found.setFlag(mt.tileOrdinalX(), mt.tileOrdinalY(), true);
|
||||
renderQueue.add(mt);
|
||||
if (map.isReadOnly() == false) {
|
||||
for (MapTile mt : map.getTiles(world, (int)loc.x, (int)loc.y, (int)loc.z)) {
|
||||
if (!found.getFlag(mt.tileOrdinalX(), mt.tileOrdinalY())) {
|
||||
found.setFlag(mt.tileOrdinalX(), mt.tileOrdinalY(), true);
|
||||
renderQueue.add(mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!updaterender) { /* Only add other seed points for fullrender */
|
||||
|
@ -687,6 +694,7 @@ public class MapManager {
|
|||
}
|
||||
});
|
||||
rslt.add(future);
|
||||
|
||||
}
|
||||
}
|
||||
/* Now, do our render (first one) */
|
||||
|
@ -922,6 +930,8 @@ public class MapManager {
|
|||
f.get();
|
||||
} catch (CancellationException cx) {
|
||||
return;
|
||||
} catch (InterruptedException cx) {
|
||||
return;
|
||||
} catch (ExecutionException ex) {
|
||||
Log.severe("Error while checking world times: ", ex.getCause());
|
||||
} catch (Exception ix) {
|
||||
|
@ -1064,6 +1074,10 @@ public class MapManager {
|
|||
tiles.clear();
|
||||
for(DynmapWorld w : worlds) {
|
||||
for(MapTypeState mts : w.mapstate) {
|
||||
if (mts.type.isReadOnly()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(mts.getNextInvalidTileCoord(coord)) {
|
||||
mts.type.addMapTiles(tiles, w, coord.x, coord.y);
|
||||
mts.validateTile(coord.x, coord.y);
|
||||
|
@ -1141,7 +1155,9 @@ public class MapManager {
|
|||
if(progressinterval < 100) progressinterval = 100;
|
||||
saverestorepending = configuration.getBoolean("saverestorepending", true);
|
||||
tileupdatedelay = configuration.getInteger("tileupdatedelay", 30);
|
||||
|
||||
defaulttilescale = configuration.getInteger("defaulttilescale", 0);
|
||||
if (defaulttilescale < 0) defaulttilescale = 0;
|
||||
if (defaulttilescale > 4) defaulttilescale = 4;
|
||||
tpslimit_updaterenders = configuration.getDouble("update-min-tps", 18.0);
|
||||
if (tpslimit_updaterenders > 19.5) tpslimit_updaterenders = 19.5;
|
||||
tpslimit_fullrenders = configuration.getDouble("fullrender-min-tps", 18.0);
|
||||
|
@ -1893,6 +1909,10 @@ public class MapManager {
|
|||
}
|
||||
if(world == null) continue;
|
||||
for (MapTypeState mts : world.mapstate) {
|
||||
if (mts.type.isReadOnly()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<TileFlags.TileCoord> tiles = mts.type.getTileCoords(world, evt.x, evt.y, evt.z);
|
||||
invalidates += mts.invalidateTiles(tiles);
|
||||
}
|
||||
|
@ -1925,6 +1945,10 @@ public class MapManager {
|
|||
if(world == null) continue;
|
||||
int invalidates = 0;
|
||||
for (MapTypeState mts : world.mapstate) {
|
||||
if (mts.type.isReadOnly()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<TileFlags.TileCoord> tiles = mts.type.getTileCoords(world, evt.xmin, evt.ymin, evt.zmin, evt.xmax, evt.ymax, evt.zmax);
|
||||
invalidates += mts.invalidateTiles(tiles);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ public abstract class MapTile {
|
|||
public abstract boolean render(MapChunkCache cache, String mapname);
|
||||
public abstract List<DynmapChunk> getRequiredChunks();
|
||||
public abstract MapTile[] getAdjecentTiles();
|
||||
public abstract int getTileSize();
|
||||
|
||||
public DynmapWorld getDynmapWorld() {
|
||||
return world;
|
||||
|
|
|
@ -10,6 +10,10 @@ import org.json.simple.JSONObject;
|
|||
|
||||
public abstract class MapType {
|
||||
private boolean is_protected;
|
||||
/**
|
||||
* Is the map type read-only? (i.e. should not be updated by renderer)
|
||||
*/
|
||||
private boolean is_readonly;
|
||||
protected int tileupdatedelay;
|
||||
|
||||
public enum ImageVariant {
|
||||
|
@ -30,13 +34,15 @@ public abstract class MapType {
|
|||
}
|
||||
|
||||
public enum ImageEncoding {
|
||||
PNG("png", "image/png"), JPG("jpg", "image/jpeg"), WEBP("webp", "image/webp");
|
||||
PNG("png", "image/png", true), JPG("jpg", "image/jpeg", false), WEBP("webp", "image/webp", true);
|
||||
public final String ext;
|
||||
public final String mimetype;
|
||||
public final boolean hasAlpha;
|
||||
|
||||
ImageEncoding(String ext, String mime) {
|
||||
ImageEncoding(String ext, String mime, boolean has_alpha) {
|
||||
this.ext = ext;
|
||||
this.mimetype = mime;
|
||||
this.hasAlpha = has_alpha;
|
||||
}
|
||||
public String getFileExt() { return ext; }
|
||||
public String getContentType() { return mimetype; }
|
||||
|
@ -47,6 +53,15 @@ public abstract class MapType {
|
|||
return v[ix];
|
||||
return null;
|
||||
}
|
||||
public static ImageEncoding fromContentType(String ct) {
|
||||
ImageEncoding[] v = values();
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
if (v[i].mimetype.equalsIgnoreCase(ct)) {
|
||||
return v[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static ImageEncoding fromExt(String x) {
|
||||
ImageEncoding[] v = values();
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
|
@ -115,6 +130,8 @@ public abstract class MapType {
|
|||
|
||||
public abstract List<DynmapChunk> getRequiredChunks(MapTile tile);
|
||||
|
||||
public abstract int getTileSize();
|
||||
|
||||
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld w) {
|
||||
}
|
||||
|
||||
|
@ -194,6 +211,26 @@ public abstract class MapType {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Is the map type read-only? (i.e. should not be updated by renderer)
|
||||
* @return true if read-only
|
||||
*/
|
||||
public boolean isReadOnly() {
|
||||
return is_readonly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set read-only state of map type
|
||||
* @param r - true if read-only
|
||||
* @return true if state changed
|
||||
*/
|
||||
public boolean setReadOnly(boolean r) {
|
||||
if(is_readonly != r) {
|
||||
is_readonly = r;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public abstract String getPrefix();
|
||||
|
||||
public int getTileUpdateDelay(DynmapWorld w) {
|
||||
|
|
|
@ -22,6 +22,7 @@ public class MapTypeState {
|
|||
private TileFlags.Iterator zoomOutInvIter = null;
|
||||
private int zoomOutInvIterLevel = -1;
|
||||
private final int zoomOutLevels;
|
||||
public final int tileSize;
|
||||
|
||||
public MapTypeState(DynmapWorld world, MapType mt) {
|
||||
type = mt;
|
||||
|
@ -32,6 +33,7 @@ public class MapTypeState {
|
|||
zoomOutInv.add(null);
|
||||
zoomOutInvAccum.add(null);
|
||||
}
|
||||
tileSize = mt.getTileSize();
|
||||
}
|
||||
public void setInvalidatePeriod(long inv_per_in_secs) {
|
||||
invTSPeriod = inv_per_in_secs * NANOS_PER_SECOND;
|
||||
|
|
|
@ -174,7 +174,6 @@ public class PlayerFaces {
|
|||
// Copy face and overlay to icon
|
||||
copyLayersToTarget(img, 8*scale, 8*scale, 40*scale, 8*scale, 8*scale, 8*scale, faceOriginal, 0, 8*scale);
|
||||
|
||||
int[] faceaccessory = new int[64]; /* 8x8 of face accessory */
|
||||
/* Get buffered image for face at 8x8 */
|
||||
DynmapBufferedImage face8x8 = DynmapBufferedImage.allocateBufferedImage(8, 8);
|
||||
Image face8x8_image = faceOriginal.getScaledInstance(8,8,BufferedImage.SCALE_SMOOTH);
|
||||
|
|
|
@ -7,11 +7,11 @@ import java.io.IOException;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.dynmap.common.DynmapCommandSender;
|
||||
|
@ -26,8 +26,9 @@ public class WebAuthManager {
|
|||
public static final String WEBAUTHFILE = "webauth.txt";
|
||||
private static final String HASHSALT = "$HASH_SALT$";
|
||||
private static final String PWDHASH_PREFIX = "hash.";
|
||||
private Random rnd = new Random();
|
||||
private SecureRandom rnd = new SecureRandom();
|
||||
private DynmapCore core;
|
||||
private String publicRegistrationURL;
|
||||
|
||||
public WebAuthManager(DynmapCore core) {
|
||||
this.core = core;
|
||||
|
@ -202,7 +203,8 @@ public class WebAuthManager {
|
|||
pending_registrations.put(uid.toLowerCase(), regkey.toLowerCase());
|
||||
sender.sendMessage("Registration pending for user ID: " + uid);
|
||||
sender.sendMessage("Registration code: " + regkey);
|
||||
sender.sendMessage("Enter ID and code on registration web page (login.html) to complete registration");
|
||||
publicRegistrationURL = core.configuration.getString("publicURL", "index.html");
|
||||
sender.sendMessage("Enter ID and code on registration web page (" + publicRegistrationURL.toString() + ") to complete registration");
|
||||
if(other) {
|
||||
DynmapPlayer p = core.getServer().getPlayer(uid);
|
||||
if(p != null) {
|
||||
|
|
|
@ -3,8 +3,8 @@ package org.dynmap.common;
|
|||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.hdmap.HDBlockModels;
|
||||
|
||||
/* Generic biome mapping */
|
||||
|
@ -20,7 +20,7 @@ public class BiomeMap {
|
|||
public static final BiomeMap EXTREME_HILLS = new BiomeMap(3, "EXTREME_HILLS", 0.2, 0.3, "minecraft:mountains");
|
||||
public static final BiomeMap FOREST = new BiomeMap(4, "FOREST", 0.7, 0.8, "minecraft:forest");
|
||||
public static final BiomeMap TAIGA = new BiomeMap(5, "TAIGA", 0.05, 0.8, "minecraft:taiga");
|
||||
public static final BiomeMap SWAMPLAND = new BiomeMap(6, "SWAMPLAND", 0.8, 0.9, 0xE0FFAE, 0x4E0E4E, 0x4E0E4E, "minecraft:swamp");
|
||||
public static final BiomeMap SWAMPLAND = new BiomeMap(6, "SWAMPLAND", 0.8, 0.9, 0xE0FFAE, 0x2e282a, 0x902c52, "minecraft:swamp");
|
||||
public static final BiomeMap RIVER = new BiomeMap(7, "RIVER", "minecraft:river");
|
||||
public static final BiomeMap HELL = new BiomeMap(8, "HELL", 2.0, 0.0, "minecraft:nether");
|
||||
public static final BiomeMap SKY = new BiomeMap(9, "SKY", "minecraft:the_end");
|
||||
|
@ -45,6 +45,7 @@ public class BiomeMap {
|
|||
private int watercolormult;
|
||||
private int grassmult;
|
||||
private int foliagemult;
|
||||
private Optional<?> biomeObj = Optional.empty();
|
||||
private final String id;
|
||||
private final String resourcelocation;
|
||||
private final int index;
|
||||
|
@ -62,7 +63,7 @@ public class BiomeMap {
|
|||
new BiomeMap(26, "COLD_BEACH", 0.05, 0.3, "minecraft:snowy_beach");
|
||||
new BiomeMap(27, "BIRCH_FOREST", 0.6, 0.6, "minecraft:birch_forest");
|
||||
new BiomeMap(28, "BIRCH_FOREST_HILLS", 0.6, 0.6, "minecraft:birch_forest_hills");
|
||||
new BiomeMap(29, "ROOFED_FOREST", 0.7, 0.8, "minecraft:dark_forest");
|
||||
new BiomeMap(29, "ROOFED_FOREST", 0.7, 0.8, 0xFFFFFF, 0x28340A, 0, "minecraft:dark_forest");
|
||||
new BiomeMap(30, "COLD_TAIGA", -0.5, 0.4, "minecraft:snowy_taiga");
|
||||
new BiomeMap(31, "COLD_TAIGA_HILLS", -0.5, 0.4, "minecraft:snowy_taiga_hills");
|
||||
new BiomeMap(32, "MEGA_TAIGA", 0.3, 0.8, "minecraft:giant_tree_taiga");
|
||||
|
@ -70,30 +71,32 @@ public class BiomeMap {
|
|||
new BiomeMap(34, "EXTREME_HILLS_PLUS", 0.2, 0.3, "minecraft:wooded_mountains");
|
||||
new BiomeMap(35, "SAVANNA", 1.2, 0.0, "minecraft:savanna");
|
||||
new BiomeMap(36, "SAVANNA_PLATEAU", 1.0, 0.0, "minecraft:savanna_plateau");
|
||||
new BiomeMap(37, "MESA", 2.0, 0.0, "minecraft:badlands");
|
||||
new BiomeMap(38, "MESA_PLATEAU_FOREST", 2.0, 0.0, "minecraft:wooded_badlands_plateau");
|
||||
new BiomeMap(39, "MESA_PLATEAU", 2.0, 0.0, "minecraft:badlands_plateau");
|
||||
new BiomeMap(37, "MESA", 2.0, 0.0, 0xFFFFFF, 0x624c46, 0x8e5e70, "minecraft:badlands");
|
||||
new BiomeMap(129, "SUNFLOWER_PLAINS", 0.8, 0.4, "minecraft:sunflower_plains");
|
||||
new BiomeMap(130, "DESERT_MOUNTAINS", 2.0, 0.0, "minecraft:desert_lakes");
|
||||
new BiomeMap(131, "EXTREME_HILLS_MOUNTAINS", 0.2, 0.3, "minecraft:gravelly_mountains");
|
||||
new BiomeMap(132, "FLOWER_FOREST", 0.7, 0.8, "minecraft:flower_forest");
|
||||
new BiomeMap(133, "TAIGA_MOUNTAINS", 0.05, 0.8, "minecraft:taiga_mountains");
|
||||
new BiomeMap(134, "SWAMPLAND_MOUNTAINS", 0.8, 0.9, 0xE0FFAE, 0x4E0E4E, 0x4E0E4E, "minecraft:swamp_hills");
|
||||
new BiomeMap(140, "ICE_PLAINS_SPIKES", 0.0, 0.5, "minecraft:ice_spikes");
|
||||
new BiomeMap(149, "JUNGLE_MOUNTAINS", 1.2, 0.9, "minecraft:modified_jungle");
|
||||
new BiomeMap(151, "JUNGLE_EDGE_MOUNTAINS", 0.95, 0.8, "minecraft:modified_jungle_edge");
|
||||
new BiomeMap(155, "BIRCH_FOREST_MOUNTAINS", 0.6, 0.6, "minecraft:tall_birch_forest");
|
||||
new BiomeMap(156, "BIRCH_FOREST_HILLS_MOUNTAINS", 0.6, 0.6, "minecraft:tall_birch_hills");
|
||||
new BiomeMap(157, "ROOFED_FOREST_MOUNTAINS", 0.7, 0.8, "minecraft:dark_forest_hills");
|
||||
new BiomeMap(157, "ROOFED_FOREST_MOUNTAINS", 0.7, 0.8, 0xFFFFFF, 0x28340A, 0, "minecraft:dark_forest_hills");
|
||||
new BiomeMap(158, "COLD_TAIGA_MOUNTAINS", -0.5, 0.4, "minecraft:snowy_taiga_mountains");
|
||||
new BiomeMap(160, "MEGA_SPRUCE_TAIGA", 0.25, 0.8, "minecraft:giant_spruce_taiga");
|
||||
new BiomeMap(161, "MEGA_SPRUCE_TAIGA_HILLS", 0.3, 0.8, "minecraft:giant_spruce_taiga_hills");
|
||||
new BiomeMap(162, "EXTREME_HILLS_PLUS_MOUNTAINS", 0.2, 0.3, "minecraft:modified_gravelly_mountains");
|
||||
new BiomeMap(163, "SAVANNA_MOUNTAINS", 1.2, 0.0, "minecraft:shattered_savanna");
|
||||
new BiomeMap(164, "SAVANNA_PLATEAU_MOUNTAINS", 1.0, 0.0, "minecraft:shattered_savanna_plateau");
|
||||
new BiomeMap(165, "MESA_BRYCE", 2.0, 0.0, "minecraft:eroded_badlands");
|
||||
new BiomeMap(166, "MESA_PLATEAU_FOREST_MOUNTAINS", 2.0, 0.0, "minecraft:modified_wooded_badlands_plateau");
|
||||
new BiomeMap(167, "MESA_PLATEAU_MOUNTAINS", 2.0, 0.0, "minecraft:modified_badlands_plateau");
|
||||
new BiomeMap(165, "MESA_BRYCE", 2.0, 0.0,0xFFFFFF, 0x624c46, 0x8e5e70, "minecraft:eroded_badlands");
|
||||
}
|
||||
if (HDBlockModels.checkVersionRange(mcver, "1.7.0-1.17.1")) {
|
||||
new BiomeMap(38, "MESA_PLATEAU_FOREST", 2.0, 0.0, 0xFFFFFF, 0x624c46, 0x8e5e70, "minecraft:wooded_badlands_plateau");
|
||||
new BiomeMap(39, "MESA_PLATEAU", 2.0, 0.0, 0xFFFFFF, 0x624c46, 0x8e5e70, "minecraft:badlands_plateau");
|
||||
new BiomeMap(134, "SWAMPLAND_MOUNTAINS", 0.8, 0.9, 0xE0FFAE, 0x2e282a, 0x902c52, "minecraft:swamp_hills");
|
||||
new BiomeMap(166, "MESA_PLATEAU_FOREST_MOUNTAINS", 2.0, 0.0,0xFFFFFF, 0x624c46, 0x8e5e70, "minecraft:modified_wooded_badlands_plateau");
|
||||
new BiomeMap(167, "MESA_PLATEAU_MOUNTAINS", 2.0, 0.0,0xFFFFFF, 0x624c46, 0x8e5e70, "minecraft:modified_badlands_plateau");
|
||||
}
|
||||
if (HDBlockModels.checkVersionRange(mcver, "1.9.0-")) {
|
||||
new BiomeMap(127, "THE_VOID", "minecraft:the_void");
|
||||
|
@ -125,6 +128,9 @@ public class BiomeMap {
|
|||
new BiomeMap(174, "DRIPSTONE_CAVES", "minecraft:dripstone_caves");
|
||||
new BiomeMap(175, "LUSH_CAVES", "minecraft:lush_caves");
|
||||
}
|
||||
if (HDBlockModels.checkVersionRange(mcver, "1.18.0-")) {
|
||||
new BiomeMap(38, "MESA_FOREST", 2.0, 0.0, 0xFFFFFF, 0x624c46, 0x8e5e70, "minecraft:wooded_badlands");
|
||||
}
|
||||
loadDone = true;
|
||||
}
|
||||
|
||||
|
@ -298,7 +304,16 @@ public class BiomeMap {
|
|||
public boolean isDefault() {
|
||||
return isDef;
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public String toString() {
|
||||
return String.format("%s(%s)", id, resourcelocation);
|
||||
}
|
||||
public @SuppressWarnings("unchecked") <T> Optional<T> getBiomeObject() {
|
||||
return (Optional<T>) biomeObj;
|
||||
}
|
||||
public void setBiomeObject(Object biomeObj) {
|
||||
this.biomeObj = Optional.of(biomeObj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,12 @@ public interface DynmapPlayer extends DynmapCommandSender {
|
|||
* @return true if sneaking
|
||||
*/
|
||||
public boolean isSneaking();
|
||||
|
||||
/**
|
||||
* get spectator gamemode
|
||||
* @return true if gamemode spectator
|
||||
*/
|
||||
public boolean isSpectator();
|
||||
/**
|
||||
* Get health
|
||||
* @return health points
|
||||
|
|
|
@ -3,7 +3,6 @@ package org.dynmap.common.chunk;
|
|||
import java.util.Arrays;
|
||||
|
||||
import org.dynmap.renderer.DynmapBlockState;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.common.BiomeMap;
|
||||
|
||||
// Generic chunk representation
|
||||
|
|
|
@ -18,6 +18,7 @@ public class GenericChunkCache {
|
|||
};
|
||||
|
||||
private CacheHashMap snapcache;
|
||||
private final Object snapcachelock;
|
||||
private ReferenceQueue<ChunkCacheRec> refqueue;
|
||||
private long cache_attempts;
|
||||
private long cache_success;
|
||||
|
@ -50,6 +51,7 @@ public class GenericChunkCache {
|
|||
* Create snapshot cache
|
||||
*/
|
||||
public GenericChunkCache(int max_size, boolean softref) {
|
||||
snapcachelock = new Object();
|
||||
snapcache = new CacheHashMap(max_size);
|
||||
refqueue = new ReferenceQueue<ChunkCacheRec>();
|
||||
this.softref = softref;
|
||||
|
@ -62,8 +64,8 @@ public class GenericChunkCache {
|
|||
*/
|
||||
public void invalidateSnapshot(String w, int x, int y, int z) {
|
||||
String key = getKey(w, x>>4, z>>4);
|
||||
synchronized(snapcache) {
|
||||
CacheRec rec = snapcache.remove(key);
|
||||
synchronized(snapcachelock) {
|
||||
CacheRec rec = (snapcache != null) ? snapcache.remove(key) : null;
|
||||
if(rec != null) {
|
||||
snapcache.reverselookup.remove(rec.ref);
|
||||
rec.ref.clear();
|
||||
|
@ -78,8 +80,8 @@ public class GenericChunkCache {
|
|||
for(int xx = (x0>>4); xx <= (x1>>4); xx++) {
|
||||
for(int zz = (z0>>4); zz <= (z1>>4); zz++) {
|
||||
String key = getKey(w, xx, zz);
|
||||
synchronized(snapcache) {
|
||||
CacheRec rec = snapcache.remove(key);
|
||||
synchronized(snapcachelock) {
|
||||
CacheRec rec = (snapcache != null) ? snapcache.remove(key) : null;
|
||||
if(rec != null) {
|
||||
snapcache.reverselookup.remove(rec.ref);
|
||||
rec.ref.clear();
|
||||
|
@ -97,8 +99,8 @@ public class GenericChunkCache {
|
|||
processRefQueue();
|
||||
ChunkCacheRec ss = null;
|
||||
CacheRec rec;
|
||||
synchronized(snapcache) {
|
||||
rec = snapcache.get(key);
|
||||
synchronized(snapcachelock) {
|
||||
rec = (snapcache != null) ? snapcache.get(key) : null;
|
||||
if(rec != null) {
|
||||
ss = rec.ref.get();
|
||||
if(ss == null) {
|
||||
|
@ -123,8 +125,8 @@ public class GenericChunkCache {
|
|||
rec.ref = new SoftReference<ChunkCacheRec>(ss, refqueue);
|
||||
else
|
||||
rec.ref = new WeakReference<ChunkCacheRec>(ss, refqueue);
|
||||
synchronized(snapcache) {
|
||||
CacheRec prevrec = snapcache.put(key, rec);
|
||||
synchronized(snapcachelock) {
|
||||
CacheRec prevrec = (snapcache != null) ? snapcache.put(key, rec) : null;
|
||||
if(prevrec != null) {
|
||||
snapcache.reverselookup.remove(prevrec.ref);
|
||||
}
|
||||
|
@ -137,8 +139,8 @@ public class GenericChunkCache {
|
|||
private void processRefQueue() {
|
||||
Reference<? extends ChunkCacheRec> ref;
|
||||
while((ref = refqueue.poll()) != null) {
|
||||
synchronized(snapcache) {
|
||||
String k = snapcache.reverselookup.remove(ref);
|
||||
synchronized(snapcachelock) {
|
||||
String k = (snapcache != null) ? snapcache.reverselookup.remove(ref) : null;
|
||||
if(k != null) {
|
||||
snapcache.remove(k);
|
||||
}
|
||||
|
@ -164,11 +166,13 @@ public class GenericChunkCache {
|
|||
* Cleanup
|
||||
*/
|
||||
public void cleanup() {
|
||||
if(snapcache != null) {
|
||||
snapcache.clear();
|
||||
snapcache.reverselookup.clear();
|
||||
snapcache.reverselookup = null;
|
||||
snapcache = null;
|
||||
}
|
||||
synchronized(snapcachelock) {
|
||||
if(snapcache != null) {
|
||||
snapcache.clear();
|
||||
snapcache.reverselookup.clear();
|
||||
snapcache.reverselookup = null;
|
||||
snapcache = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package org.dynmap.common.chunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.DynmapCore;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.common.BiomeMap;
|
||||
import org.dynmap.common.chunk.GenericChunkCache.ChunkCacheRec;
|
||||
import org.dynmap.hdmap.HDBlockModels;
|
||||
|
@ -24,7 +25,6 @@ import org.dynmap.utils.VisibilityLimit;
|
|||
* Abstract container for handling map cache and map iterator, using DynmapChunks
|
||||
*/
|
||||
public abstract class GenericMapChunkCache extends MapChunkCache {
|
||||
private static boolean init = false;
|
||||
protected DynmapWorld dw;
|
||||
private int nsect;
|
||||
private int sectoff; // Offset for sake of negative section indexes
|
||||
|
@ -39,6 +39,7 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
private int snapcnt;
|
||||
private GenericChunk[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */
|
||||
private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */
|
||||
private AtomicInteger loadingChunks = new AtomicInteger(0); //the amount of threads loading chunks at this moment, used by async loading
|
||||
|
||||
private static final BlockStep unstep[] = { BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS,
|
||||
BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS };
|
||||
|
@ -53,11 +54,13 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
private DynmapBlockState blk;
|
||||
private final int worldheight;
|
||||
private final int ymin;
|
||||
private final int sealevel;
|
||||
|
||||
OurMapIterator(int x0, int y0, int z0) {
|
||||
initialize(x0, y0, z0);
|
||||
worldheight = dw.worldheight;
|
||||
ymin = dw.minY;
|
||||
sealevel = dw.sealevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -180,7 +183,7 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
for (int dz = -1; dz <= 1; dz++) {
|
||||
BiomeMap bm = getBiomeRel(dx, dz);
|
||||
if (bm == BiomeMap.NULL) continue;
|
||||
int rmult = bm.getModifiedGrassMultiplier(colormap[bm.biomeLookup()]);
|
||||
int rmult = getGrassColor(bm, colormap, getX() + dx, getZ() + dz);
|
||||
raccum += (rmult >> 16) & 0xFF;
|
||||
gaccum += (rmult >> 8) & 0xFF;
|
||||
baccum += rmult & 0xFF;
|
||||
|
@ -211,7 +214,7 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
for (int dz = -1; dz <= 1; dz++) {
|
||||
BiomeMap bm = getBiomeRel(dx, dz);
|
||||
if (bm == BiomeMap.NULL) continue;
|
||||
int rmult = bm.getModifiedFoliageMultiplier(colormap[bm.biomeLookup()]);
|
||||
int rmult = getFoliageColor(bm, colormap, getX() + dx, getZ() + dz);
|
||||
raccum += (rmult >> 16) & 0xFF;
|
||||
gaccum += (rmult >> 8) & 0xFF;
|
||||
baccum += rmult & 0xFF;
|
||||
|
@ -482,7 +485,16 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
public final int getWorldHeight() {
|
||||
return worldheight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getWorldYMin() {
|
||||
return ymin;
|
||||
}
|
||||
/**
|
||||
* Get world sealevel
|
||||
*/
|
||||
public final int getWorldSeaLevel() {
|
||||
return sealevel;
|
||||
}
|
||||
@Override
|
||||
public final long getBlockKey() {
|
||||
return (((chunkindex * (worldheight - ymin)) + (y - ymin)) << 8) | (bx << 4) | bz;
|
||||
|
@ -545,6 +557,14 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
}
|
||||
}
|
||||
|
||||
public int getGrassColor(BiomeMap bm, int[] colormap, int x, int z) {
|
||||
return bm.getModifiedGrassMultiplier(colormap[bm.biomeLookup()]);
|
||||
}
|
||||
|
||||
public int getFoliageColor(BiomeMap bm, int[] colormap, int x, int z) {
|
||||
return bm.getModifiedFoliageMultiplier(colormap[bm.biomeLookup()]);
|
||||
}
|
||||
|
||||
private class OurEndMapIterator extends OurMapIterator {
|
||||
OurEndMapIterator(int x0, int y0, int z0) {
|
||||
super(x0, y0, z0);
|
||||
|
@ -699,6 +719,14 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
protected abstract GenericChunk getLoadedChunk(DynmapChunk ch);
|
||||
// Load generic chunk from unloaded chunk
|
||||
protected abstract GenericChunk loadChunk(DynmapChunk ch);
|
||||
// Load generic chunk from existing and already loaded chunk async
|
||||
protected Supplier<GenericChunk> getLoadedChunkAsync(DynmapChunk ch) {
|
||||
throw new IllegalStateException("Not implemeted");
|
||||
}
|
||||
// Load generic chunks from unloaded chunk async
|
||||
protected Supplier<GenericChunk> loadChunkAsync(DynmapChunk ch){
|
||||
throw new IllegalStateException("Not implemeted");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read NBT data from loaded chunks - needs to be called from server/world
|
||||
|
@ -756,10 +784,84 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read NBT data from loaded chunks - do not needs to be called from server/world <p>
|
||||
* Will throw {@link IllegalStateException} if not supporting
|
||||
*/
|
||||
public void getLoadedChunksAsync() {
|
||||
class SimplePair { //simple pair of the supplier that finishes read async, and a consumer that also finish his work async
|
||||
final Supplier<GenericChunk> supplier;
|
||||
final BiConsumer<GenericChunk, Long> consumer;
|
||||
|
||||
SimplePair(Supplier<GenericChunk> supplier, BiConsumer<GenericChunk, Long> consumer) {
|
||||
this.supplier = supplier;
|
||||
this.consumer = consumer;
|
||||
}
|
||||
}
|
||||
if (!dw.isLoaded()) {
|
||||
isempty = true;
|
||||
unloadChunks();
|
||||
return;
|
||||
}
|
||||
List<SimplePair> lastApply = new ArrayList<>();
|
||||
for (DynmapChunk dynmapChunk : chunks) {
|
||||
long startTime = System.nanoTime();
|
||||
int chunkIndex = (dynmapChunk.x - x_min) + (dynmapChunk.z - z_min) * x_dim;
|
||||
if (snaparray[chunkIndex] != null)
|
||||
continue; // Skip if already processed
|
||||
|
||||
boolean vis = isChunkVisible(dynmapChunk);
|
||||
|
||||
/* Check if cached chunk snapshot found */
|
||||
if (tryChunkCache(dynmapChunk, vis)) {
|
||||
endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT);
|
||||
}
|
||||
// If chunk is loaded and not being unloaded, we're grabbing its NBT data
|
||||
else {
|
||||
// Get generic chunk from already loaded chunk, if we can
|
||||
Supplier<GenericChunk> supplier = getLoadedChunkAsync(dynmapChunk);
|
||||
long startPause = System.nanoTime();
|
||||
BiConsumer<GenericChunk, Long> consumer = (ss, reloadTime) -> {
|
||||
if (ss == null) return;
|
||||
long pause = reloadTime - startPause;
|
||||
if (vis) { // If visible
|
||||
prepChunkSnapshot(dynmapChunk, ss);
|
||||
} else {
|
||||
if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) {
|
||||
ss = getStone();
|
||||
} else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) {
|
||||
ss = getOcean();
|
||||
} else {
|
||||
ss = getEmpty();
|
||||
}
|
||||
}
|
||||
snaparray[chunkIndex] = ss;
|
||||
endChunkLoad(startTime - pause, ChunkStats.LOADED_CHUNKS);
|
||||
|
||||
};
|
||||
lastApply.add(new SimplePair(supplier, consumer));
|
||||
}
|
||||
}
|
||||
//impact on the main thread should be minimal, so we plan and finish the work after main thread finished it's part
|
||||
lastApply.forEach(simplePair -> {
|
||||
long reloadWork = System.nanoTime();
|
||||
simplePair.consumer.accept(simplePair.supplier.get(), reloadWork);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int loadChunks(int max_to_load) {
|
||||
return getLoadedChunks() + readChunks(max_to_load);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all chunks in the world asynchronously.
|
||||
* <p>
|
||||
* If it is not supported, it will throw {@link IllegalStateException}
|
||||
*/
|
||||
public void loadChunksAsync() {
|
||||
getLoadedChunksAsync();
|
||||
readChunksAsync();
|
||||
}
|
||||
|
||||
public int readChunks(int max_to_load) {
|
||||
|
@ -842,6 +944,102 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* It loads chunks from the cache or from the world, and if the chunk is not visible, it fills it with stone, ocean or
|
||||
* empty chunk
|
||||
* <p>
|
||||
* if it's not supported, will throw {@link IllegalStateException}
|
||||
*/
|
||||
public void readChunksAsync() {
|
||||
class SimplePair { //pair of the chunk and the data which is readed async
|
||||
private final Supplier<GenericChunk> supplier;
|
||||
private final DynmapChunk chunk;
|
||||
|
||||
SimplePair(DynmapChunk chunk) {
|
||||
this.chunk = chunk;
|
||||
this.supplier = loadChunkAsync(chunk);
|
||||
}
|
||||
}
|
||||
if (!dw.isLoaded()) {
|
||||
isempty = true;
|
||||
unloadChunks();
|
||||
return;
|
||||
}
|
||||
|
||||
List<DynmapChunk> chunks;
|
||||
if (iterator == null) {
|
||||
iterator = Collections.emptyListIterator();
|
||||
chunks = new ArrayList<>(this.chunks);
|
||||
} else {
|
||||
chunks = new ArrayList<>();
|
||||
iterator.forEachRemaining(chunks::add);
|
||||
}
|
||||
//if before increent was 0, means that we are the first, so we need to set this
|
||||
if (loadingChunks.getAndIncrement() == 0) {
|
||||
DynmapCore.setIgnoreChunkLoads(true);
|
||||
}
|
||||
|
||||
try {
|
||||
List<DynmapChunk> cached = new ArrayList<>();
|
||||
List<SimplePair> notCached = new ArrayList<>();
|
||||
|
||||
iterator.forEachRemaining(chunks::add);
|
||||
chunks.stream()
|
||||
.filter(chunk -> snaparray[(chunk.x - x_min) + (chunk.z - z_min) * x_dim] == null)
|
||||
.forEach(chunk -> {
|
||||
if (cache.getSnapshot(dw.getName(), chunk.x, chunk.z) == null) {
|
||||
notCached.add(new SimplePair(chunk));
|
||||
} else {
|
||||
cached.add(chunk);
|
||||
}
|
||||
});
|
||||
|
||||
cached.forEach(chunk -> {
|
||||
long startTime = System.nanoTime();
|
||||
tryChunkCache(chunk, isChunkVisible(chunk));
|
||||
endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT);
|
||||
});
|
||||
notCached.forEach(chunkSupplier -> {
|
||||
long startTime = System.nanoTime();
|
||||
GenericChunk chunk = chunkSupplier.supplier.get();
|
||||
DynmapChunk dynmapChunk = chunkSupplier.chunk;
|
||||
if (chunk != null) {
|
||||
// If hidden
|
||||
if (isChunkVisible(dynmapChunk)) {
|
||||
// Prep snapshot
|
||||
prepChunkSnapshot(dynmapChunk, chunk);
|
||||
} else {
|
||||
if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) {
|
||||
chunk = getStone();
|
||||
} else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) {
|
||||
chunk = getOcean();
|
||||
} else {
|
||||
chunk = getEmpty();
|
||||
}
|
||||
}
|
||||
snaparray[(dynmapChunk.x - x_min) + (dynmapChunk.z - z_min) * x_dim] = chunk;
|
||||
endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS);
|
||||
} else {
|
||||
endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS);
|
||||
}
|
||||
});
|
||||
|
||||
isempty = true;
|
||||
/* Fill missing chunks with empty dummy chunk */
|
||||
for (int i = 0; i < snaparray.length; i++) {
|
||||
if (snaparray[i] == null) {
|
||||
snaparray[i] = getEmpty();
|
||||
} else if (!snaparray[i].isEmpty) {
|
||||
isempty = false;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (loadingChunks.decrementAndGet() == 0) {
|
||||
DynmapCore.setIgnoreChunkLoads(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if done loading
|
||||
*/
|
||||
|
@ -1097,19 +1295,19 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
bitsperblock = (statelist.length * 64) / 4096;
|
||||
dbp = new DataBitsPacked(bitsperblock, 4096, statelist);
|
||||
}
|
||||
if (bitsperblock > 8) { // Not palette
|
||||
for (int j = 0; j < 4096; j++) {
|
||||
int v = db != null ? db.get(j) : dbp.getAt(j);
|
||||
sbld.xyzBlockState(j & 0xF, (j & 0xF00) >> 8, (j & 0xF0) >> 4, DynmapBlockState.getStateByGlobalIndex(v));
|
||||
}
|
||||
}
|
||||
else {
|
||||
//if (bitsperblock > 8) { // Not palette
|
||||
// for (int j = 0; j < 4096; j++) {
|
||||
// int v = db != null ? db.get(j) : dbp.getAt(j);
|
||||
// sbld.xyzBlockState(j & 0xF, (j & 0xF00) >> 8, (j & 0xF0) >> 4, DynmapBlockState.getStateByGlobalIndex(v));
|
||||
// }
|
||||
//}
|
||||
//else {
|
||||
sbld.xyzBlockStatePalette(palette); // Set palette
|
||||
for (int j = 0; j < 4096; j++) {
|
||||
int v = db != null ? db.get(j) : dbp.getAt(j);
|
||||
sbld.xyzBlockStateInPalette(j & 0xF, (j & 0xF00) >> 8, (j & 0xF0) >> 4, (short)v);
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
if (sec.contains("BlockLight")) {
|
||||
|
@ -1125,8 +1323,10 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
|
|||
long[] bdataPacked = nbtbiomes.getLongArray("data");
|
||||
GenericNBTList bpalette = nbtbiomes.getList("palette", 8);
|
||||
GenericBitStorage bdata = null;
|
||||
if (bdataPacked.length > 0)
|
||||
bdata = nbt.makeBitStorage(bdataPacked.length, 64, bdataPacked);
|
||||
if (bdataPacked.length > 0) {
|
||||
int valsPerLong = (64 / bdataPacked.length);
|
||||
bdata = nbt.makeBitStorage((64 + valsPerLong - 1) / valsPerLong, 64, bdataPacked);
|
||||
}
|
||||
for (int j = 0; j < 64; j++) {
|
||||
int b = bdata != null ? bdata.get(j) : 0;
|
||||
sbld.xyzBiome(j & 0x3, (j & 0x30) >> 4, (j & 0xC) >> 2, BiomeMap.byBiomeResourceLocation(bpalette.getString(b)));
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.dynmap.common.chunk;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
// Generic interface for accessing an NBT Composite object
|
||||
public interface GenericNBTList {
|
||||
public int size();
|
||||
|
|
|
@ -523,6 +523,15 @@ public class OBJExport {
|
|||
case TOP:
|
||||
f.faceLine = String.format("f %d/%d %d/%d %d/%d %d/%d\n", v[0], uv[0], v[1], uv[1], v[2], uv[2], v[3], uv[3]);
|
||||
break;
|
||||
case TOPFLIP:
|
||||
f.faceLine += String.format("f %d/%d %d/%d %d/%d %d/%d\n", v[3], uv[2], v[2], uv[3], v[1], uv[0], v[0], uv[1]);
|
||||
break;
|
||||
case TOPFLIPV:
|
||||
f.faceLine = String.format("f %d/%d %d/%d %d/%d %d/%d\n", v[0], uv[0], v[1], uv[1], v[2], uv[2], v[3], uv[3]);
|
||||
break;
|
||||
case TOPFLIPHV:
|
||||
f.faceLine = String.format("f %d/%d %d/%d %d/%d %d/%d\n", v[0], uv[0], v[1], uv[1], v[2], uv[2], v[3], uv[3]);
|
||||
break;
|
||||
case BOTTOM:
|
||||
f.faceLine = String.format("f %d/%d %d/%d %d/%d %d/%d\n", v[3], uv[3], v[2], uv[2], v[1], uv[1], v[0], uv[0]);
|
||||
break;
|
||||
|
|
|
@ -22,6 +22,8 @@ import org.json.simple.JSONObject;
|
|||
public class CaveHDShader implements HDShader {
|
||||
private String name;
|
||||
private boolean iflit;
|
||||
private Color startColor;
|
||||
private Color endColor;
|
||||
private BitSet hiddenids = new BitSet();
|
||||
|
||||
private void setHidden(DynmapBlockState blk) {
|
||||
|
@ -41,7 +43,8 @@ public class CaveHDShader implements HDShader {
|
|||
public CaveHDShader(DynmapCore core, ConfigurationNode configuration) {
|
||||
name = (String) configuration.get("name");
|
||||
iflit = configuration.getBoolean("onlyiflit", false);
|
||||
|
||||
startColor = configuration.getColor("startColor", null);
|
||||
endColor = configuration.getColor("endColor", null);
|
||||
for (int i = 0; i < DynmapBlockState.getGlobalIndexMax(); i++) {
|
||||
DynmapBlockState bs = DynmapBlockState.getStateByGlobalIndex(i);
|
||||
if (bs.isAir() || bs.isWater()) {
|
||||
|
@ -115,19 +118,17 @@ public class CaveHDShader implements HDShader {
|
|||
protected MapIterator mapiter;
|
||||
protected HDMap map;
|
||||
private boolean air;
|
||||
private int yshift;
|
||||
private final int sealevel;
|
||||
private final int ymax, ymin;
|
||||
final int[] lightingTable;
|
||||
|
||||
private OurShaderState(MapIterator mapiter, HDMap map, MapChunkCache cache) {
|
||||
this.mapiter = mapiter;
|
||||
this.map = map;
|
||||
this.color = new Color();
|
||||
int wheight = mapiter.getWorldHeight();
|
||||
yshift = 0;
|
||||
while(wheight > 128) {
|
||||
wheight >>= 1;
|
||||
yshift++;
|
||||
}
|
||||
this.ymax = mapiter.getWorldHeight() - 1;
|
||||
this.ymin = mapiter.getWorldYMin();
|
||||
this.sealevel = mapiter.getWorldSeaLevel();
|
||||
if (MapManager.mapman.useBrightnessTable()) {
|
||||
lightingTable = cache.getWorld().getBrightnessTable();
|
||||
}
|
||||
|
@ -187,17 +188,27 @@ public class CaveHDShader implements HDShader {
|
|||
return false;
|
||||
}
|
||||
int cr, cg, cb;
|
||||
int mult = 256;
|
||||
int mult;
|
||||
|
||||
int ys = mapiter.getY() >> yshift;
|
||||
if (ys < 64) {
|
||||
cr = 0;
|
||||
cg = 64 + ys * 3;
|
||||
cb = 255 - ys * 4;
|
||||
} else {
|
||||
cr = (ys - 64) * 4;
|
||||
cg = 255;
|
||||
cb = 0;
|
||||
int y = mapiter.getY();
|
||||
if((startColor != null) && (endColor != null))
|
||||
{
|
||||
double interp = ((double)(y - this.ymin)) / (this.ymax - this.ymin);
|
||||
cr = (int)(((1.0 - interp) * startColor.getRed()) + (interp * endColor.getRed()));
|
||||
cg = (int)(((1.0 - interp) * startColor.getGreen()) + (interp * endColor.getGreen()));
|
||||
cb = (int)(((1.0 - interp) * startColor.getBlue()) + (interp * endColor.getBlue()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y < this.sealevel) {
|
||||
cr = 0;
|
||||
cg = 64 + ((192 * (y - this.ymin)) / (this.sealevel - this.ymin));
|
||||
cb = 255 - (255 * (y - this.ymin)) / (this.sealevel - this.ymin);
|
||||
} else {
|
||||
cr = (255 * (y - this.sealevel)) / (this.ymax - this.sealevel);
|
||||
cg = 255;
|
||||
cb = 0;
|
||||
}
|
||||
}
|
||||
/* Figure out which color to use */
|
||||
switch(ps.getLastBlockStep()) {
|
||||
|
|
|
@ -33,21 +33,21 @@ public class ChunkStatusHDShader implements HDShader {
|
|||
};
|
||||
private static HashMap<String, ChunkStatusMap> statusmap = new HashMap<String, ChunkStatusMap>();
|
||||
|
||||
private static ChunkStatusMap[] statusvals = {
|
||||
new ChunkStatusMap("empty", 0xFF0000),
|
||||
new ChunkStatusMap("structure_starts", 0xFF1493),
|
||||
new ChunkStatusMap("structure_references", 0xFF7F50),
|
||||
new ChunkStatusMap("biomes", 0xFFA500),
|
||||
new ChunkStatusMap("noise", 0xFFD700),
|
||||
new ChunkStatusMap("surface", 0xFFFF00),
|
||||
new ChunkStatusMap("carvers", 0xFFEFD5),
|
||||
new ChunkStatusMap("liquid_carvers", 0xF0E68C),
|
||||
new ChunkStatusMap("features", 0xBDB76B),
|
||||
new ChunkStatusMap("light", 0xDDA0DD),
|
||||
new ChunkStatusMap("spawn", 0xFF00FF),
|
||||
new ChunkStatusMap("heightmaps", 0x9370DB),
|
||||
new ChunkStatusMap("full", 0x32CD32),
|
||||
};
|
||||
static {
|
||||
new ChunkStatusMap("empty", 0xFF0000);
|
||||
new ChunkStatusMap("structure_starts", 0xFF1493);
|
||||
new ChunkStatusMap("structure_references", 0xFF7F50);
|
||||
new ChunkStatusMap("biomes", 0xFFA500);
|
||||
new ChunkStatusMap("noise", 0xFFD700);
|
||||
new ChunkStatusMap("surface", 0xFFFF00);
|
||||
new ChunkStatusMap("carvers", 0xFFEFD5);
|
||||
new ChunkStatusMap("liquid_carvers", 0xF0E68C);
|
||||
new ChunkStatusMap("features", 0xBDB76B);
|
||||
new ChunkStatusMap("light", 0xDDA0DD);
|
||||
new ChunkStatusMap("spawn", 0xFF00FF);
|
||||
new ChunkStatusMap("heightmaps", 0x9370DB);
|
||||
new ChunkStatusMap("full", 0x32CD32);
|
||||
}
|
||||
|
||||
final static Color unknown_color = new Color(255, 255, 255);
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@ import static org.dynmap.JSONUtils.s;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
|
@ -27,15 +25,16 @@ public class ChunkVersionHDShader implements HDShader {
|
|||
|
||||
private static class DataVersionMap {
|
||||
int dataVersion;
|
||||
String version;
|
||||
//String version;
|
||||
Color defcolor;
|
||||
DataVersionMap(int dv, String v, int c) {
|
||||
dataVersion = dv;
|
||||
version = v;
|
||||
//version = v;
|
||||
defcolor = new Color((c>>16)&0xFF, (c>>8)&0xFF, c&0xFF);
|
||||
|
||||
}
|
||||
};
|
||||
// Mapping from https://minecraft.wiki/w/Data_version
|
||||
final static DataVersionMap[] versionmap = {
|
||||
new DataVersionMap(0, "unknown", 0x202020),
|
||||
new DataVersionMap(1519, "1.13.0", 0xF9E79F),
|
||||
|
@ -59,6 +58,13 @@ public class ChunkVersionHDShader implements HDShader {
|
|||
new DataVersionMap(2730, "1.17.1", 0xEB984E),
|
||||
new DataVersionMap(2860, "1.18.0", 0xA3E4D7),
|
||||
new DataVersionMap(2865, "1.18.1", 0x48C9B0),
|
||||
new DataVersionMap(2975, "1.18.2", 0x38bfa5),
|
||||
new DataVersionMap(3105, "1.19", 0xd56f82),
|
||||
new DataVersionMap(3116, "1.19.1", 0xe196a4),
|
||||
new DataVersionMap(3120, "1.19.2", 0xe7aeb8),
|
||||
new DataVersionMap(3218, "1.19.3", 0xf8c0c8),
|
||||
new DataVersionMap(3337, "1.19.4", 0xffb6c1),
|
||||
|
||||
};
|
||||
final static Color unknown_color = new Color(255, 255, 255);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ public class CustomBlockModel extends HDBlockModel {
|
|||
super(bstate, databits, blockset);
|
||||
try {
|
||||
Class<?> cls = Class.forName(classname); /* Get class */
|
||||
render = (CustomRenderer) cls.newInstance();
|
||||
render = (CustomRenderer) cls.getDeclaredConstructor().newInstance();
|
||||
if(render.initializeRenderer(HDBlockModels.pdf, bstate.blockName, databits, classparm) == false) {
|
||||
Log.severe("Error loading custom renderer - " + classname);
|
||||
render = null;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.dynmap.hdmap;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -255,7 +256,7 @@ public class HDBlockModels {
|
|||
}
|
||||
}
|
||||
} catch (IOException iox) {
|
||||
Log.severe("Error processing nodel files");
|
||||
Log.severe("Error processing model files");
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try { in.close(); } catch (IOException iox) {}
|
||||
|
@ -317,6 +318,8 @@ public class HDBlockModels {
|
|||
double[] to = new double[3];
|
||||
double xrot = 0, yrot = 0, zrot = 0;
|
||||
double xrotorig = 8, yrotorig = 8, zrotorig = 8;
|
||||
int modrotx = 0, modroty = 0, modrotz = 0; // Model level rotation
|
||||
boolean shade = true;
|
||||
ArrayList<ModelBoxSide> sides = new ArrayList<ModelBoxSide>();
|
||||
};
|
||||
|
||||
|
@ -354,7 +357,7 @@ public class HDBlockModels {
|
|||
int layerbits = 0;
|
||||
int rownum = 0;
|
||||
int scale = 0;
|
||||
rdr = new LineNumberReader(new InputStreamReader(in));
|
||||
rdr = new LineNumberReader(new BufferedReader(new InputStreamReader(in)));
|
||||
while ((line = rdr.readLine()) != null) {
|
||||
boolean skip = false;
|
||||
int lineNum = rdr.getLineNumber();
|
||||
|
@ -677,6 +680,12 @@ public class HDBlockModels {
|
|||
else if(av[0].equals("visibility")) {
|
||||
if(av[1].equals("top"))
|
||||
p_sidevis = SideVisible.TOP;
|
||||
else if(av[1].equals("topflip"))
|
||||
p_sidevis = SideVisible.TOPFLIP;
|
||||
else if(av[1].equals("topflipv"))
|
||||
p_sidevis = SideVisible.TOPFLIPV;
|
||||
else if(av[1].equals("topfliphv"))
|
||||
p_sidevis = SideVisible.TOPFLIPHV;
|
||||
else if(av[1].equals("bottom"))
|
||||
p_sidevis = SideVisible.BOTTOM;
|
||||
else if(av[1].equals("flip"))
|
||||
|
@ -912,12 +921,15 @@ public class HDBlockModels {
|
|||
String[] prms = av[1].split(":");
|
||||
|
||||
ModelBox box = new ModelBox();
|
||||
if (prms.length > 0) { // Handle from (from-x/y/z)
|
||||
if (prms.length > 0) { // Handle from (from-x/y/z or from-x/y/z/shadow)
|
||||
String[] xyz = prms[0].split("/");
|
||||
if (xyz.length == 3) {
|
||||
if ((xyz.length == 3) || (xyz.length == 4)) {
|
||||
box.from[0] = Double.parseDouble(xyz[0]);
|
||||
box.from[1] = Double.parseDouble(xyz[1]);
|
||||
box.from[2] = Double.parseDouble(xyz[2]);
|
||||
if ((xyz.length >= 4) && (xyz[3].equals("false"))) {
|
||||
box.shade = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log.severe("Invalid modellist FROM value (" + prms[0] + " at line " + lineNum);
|
||||
|
@ -945,9 +957,17 @@ public class HDBlockModels {
|
|||
}
|
||||
}
|
||||
// Rest are faces (<side - upnsew>/<txtidx>/umin/vmin/umax/vmax> or <<side - upnsew>/<txtidx>)
|
||||
// OR R/mrx/mry/mrz for model rotation
|
||||
for (int faceidx = 2; faceidx < prms.length; faceidx++) {
|
||||
String v = prms[faceidx];
|
||||
String[] flds = v.split("/");
|
||||
// If rotation
|
||||
if (flds[0].equals("R") && (flds.length == 4)) {
|
||||
box.modrotx = Integer.parseInt(flds[1]);
|
||||
box.modroty = Integer.parseInt(flds[2]);
|
||||
box.modrotz = Integer.parseInt(flds[3]);
|
||||
continue;
|
||||
}
|
||||
ModelBoxSide side = new ModelBoxSide();
|
||||
side.rot = null;
|
||||
if ((flds.length != 2) && (flds.length != 6)) {
|
||||
|
@ -1000,24 +1020,31 @@ public class HDBlockModels {
|
|||
for (ModelBox bl : boxes) {
|
||||
// Loop through faces
|
||||
for (ModelBoxSide side : bl.sides) {
|
||||
PatchDefinition patch = pdf.getModelFace(bl.from, bl.to, side.side, side.uv, side.rot, side.textureid);
|
||||
PatchDefinition patch = pdf.getModelFace(bl.from, bl.to, side.side, side.uv, side.rot, bl.shade, side.textureid);
|
||||
if (patch != null) {
|
||||
// If any rotations, apply them here
|
||||
if ((bl.xrot != 0) || (bl.yrot != 0) || (bl.zrot != 0)) {
|
||||
patch = pdf.getPatch(patch, -bl.xrot, -bl.yrot, -bl.zrot,
|
||||
new Vector3D(bl.xrotorig / 16, bl.yrotorig / 16, bl.zrotorig / 16),
|
||||
patch.textureindex);
|
||||
if (patch == null) continue;
|
||||
}
|
||||
// If model rotation, apply too
|
||||
if ((bl.modrotx != 0) || (bl.modroty != 0) || (bl.modrotz != 0)) {
|
||||
patch = pdf.getPatch(patch, bl.modrotx, bl.modroty, bl.modrotz, patch.textureindex);
|
||||
if (patch == null) continue;
|
||||
}
|
||||
pd.add(patch);
|
||||
}
|
||||
else {
|
||||
Log.severe(String.format("Invalid modellist patch for box %f/%f/%f:%f/%f/%f side %s at line %d", bl.from[0], bl.from[1], bl.from[2], bl.to[0], bl.to[1], bl.to[2], side.side, lineNum));
|
||||
Log.severe(String.format("Invalid modellist patch for box %.02f/%.02f/%.02f:%.02f/%.02f/%.02f side %s at line %d", bl.from[0], bl.from[1], bl.from[2], bl.to[0], bl.to[1], bl.to[2], side.side, lineNum));
|
||||
Log.verboseinfo(String.format("line = %s:%s", typeid, line));
|
||||
}
|
||||
}
|
||||
}
|
||||
PatchDefinition[] patcharray = new PatchDefinition[pd.size()];
|
||||
for (int i = 0; i < patcharray.length; i++) {
|
||||
patcharray[i] = pd.get(i);
|
||||
patcharray[i] = pd.get(i);
|
||||
}
|
||||
if (patcharray.length > max_patches)
|
||||
max_patches = patcharray.length;
|
||||
|
|
|
@ -2,12 +2,9 @@ package org.dynmap.hdmap;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dynmap.hdmap.TexturePack;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.hdmap.HDBlockModels;
|
||||
import org.dynmap.hdmap.TexturePack.BlockTransparency;
|
||||
import org.dynmap.hdmap.TexturePack.ColorizingData;
|
||||
import org.dynmap.renderer.CustomColorMultiplier;
|
||||
|
|
|
@ -34,6 +34,7 @@ public class HDMap extends MapType {
|
|||
private MapType.ImageFormat imgformat;
|
||||
private int bgcolornight;
|
||||
private int bgcolorday;
|
||||
private int tilescale;
|
||||
private String title;
|
||||
private String icon;
|
||||
private String bg_cfg;
|
||||
|
@ -140,6 +141,9 @@ public class HDMap extends MapType {
|
|||
this.mapzoomin = configuration.getInteger("mapzoomin", 2);
|
||||
this.mapzoomout = configuration.getInteger("mapzoomout", this.mapzoomout);
|
||||
this.boostzoom = configuration.getInteger("boostzoom", 0);
|
||||
this.tilescale = configuration.getInteger("tilescale", core.getMapManager().getDefaultTileScale()); // 0 = 128, 1 = 256, ...
|
||||
if (this.tilescale <= 0) this.tilescale = 0;
|
||||
if (this.tilescale >= 4) this.tilescale = 4; // Limit to 2k x 2k
|
||||
if(this.boostzoom < 0) this.boostzoom = 0;
|
||||
if(this.boostzoom > 3) this.boostzoom = 3;
|
||||
// Map zoom in must be at least as big as boost zoom
|
||||
|
@ -149,6 +153,7 @@ public class HDMap extends MapType {
|
|||
this.append_to_world = configuration.getString("append_to_world", "");
|
||||
setProtected(configuration.getBoolean("protected", false));
|
||||
setTileUpdateDelay(configuration.getInteger("tileupdatedelay", -1));
|
||||
setReadOnly(configuration.getBoolean("readonly", false));
|
||||
}
|
||||
|
||||
public ConfigurationNode saveConfiguration() {
|
||||
|
@ -167,6 +172,7 @@ public class HDMap extends MapType {
|
|||
cn.put("mapzoomin", mapzoomin);
|
||||
cn.put("mapzoomout", mapzoomout);
|
||||
cn.put("boostzoom", boostzoom);
|
||||
cn.put("tilescale", tilescale);
|
||||
if(bg_cfg != null)
|
||||
cn.put("background", bg_cfg);
|
||||
if(bg_day_cfg != null)
|
||||
|
@ -175,6 +181,7 @@ public class HDMap extends MapType {
|
|||
cn.put("backgroundnight", bg_night_cfg);
|
||||
cn.put("append_to_world", append_to_world);
|
||||
cn.put("protected", isProtected());
|
||||
cn.put("readonly", isReadOnly());
|
||||
if(this.tileupdatedelay > 0) {
|
||||
cn.put("tileupdatedelay", this.tileupdatedelay);
|
||||
}
|
||||
|
@ -185,15 +192,18 @@ public class HDMap extends MapType {
|
|||
public final HDPerspective getPerspective() { return perspective; }
|
||||
public final HDLighting getLighting() { return lighting; }
|
||||
public final int getBoostZoom() { return boostzoom; }
|
||||
@Override
|
||||
public final int getTileSize() { return 128 << tilescale; }
|
||||
public final int getTileScale() { return tilescale; }
|
||||
|
||||
@Override
|
||||
public List<TileFlags.TileCoord> getTileCoords(DynmapWorld w, int x, int y, int z) {
|
||||
return perspective.getTileCoords(w, x, y, z);
|
||||
return perspective.getTileCoords(w, x, y, z, tilescale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TileFlags.TileCoord> getTileCoords(DynmapWorld w, int minx, int miny, int minz, int maxx, int maxy, int maxz) {
|
||||
return perspective.getTileCoords(w, minx, miny, minz, maxx, maxy, maxz);
|
||||
return perspective.getTileCoords(w, minx, miny, minz, maxx, maxy, maxz, tilescale);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -270,6 +280,7 @@ public class HDMap extends MapType {
|
|||
s(o, "mapzoomout", (world.getExtraZoomOutLevels()+mapzoomout));
|
||||
s(o, "mapzoomin", mapzoomin);
|
||||
s(o, "boostzoom", boostzoom);
|
||||
s(o, "tilescale", tilescale);
|
||||
s(o, "protected", isProtected());
|
||||
s(o, "image-format", imgformat.getFileExt());
|
||||
if(append_to_world.length() > 0)
|
||||
|
@ -403,6 +414,13 @@ public class HDMap extends MapType {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
public boolean setTileScale(int mzi) {
|
||||
if(mzi != this.tilescale) {
|
||||
this.tilescale = mzi;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean setPerspective(HDPerspective p) {
|
||||
if(perspective != p) {
|
||||
perspective = p;
|
||||
|
@ -450,7 +468,7 @@ public class HDMap extends MapType {
|
|||
|
||||
@Override
|
||||
public void addMapTiles(List<MapTile> list, DynmapWorld w, int tx, int ty) {
|
||||
list.add(new HDMapTile(w, this.perspective, tx, ty, boostzoom));
|
||||
list.add(new HDMapTile(w, this.perspective, tx, ty, boostzoom, tilescale));
|
||||
}
|
||||
|
||||
private static final ImageVariant[] dayVariant = { ImageVariant.STANDARD, ImageVariant.DAY };
|
||||
|
|
|
@ -126,10 +126,17 @@ public class HDMapManager {
|
|||
for(MapType map : w.maps) {
|
||||
if(map instanceof HDMap) {
|
||||
HDMap hdmap = (HDMap)map;
|
||||
if((hdmap.getPerspective() == tile.perspective) && (hdmap.getBoostZoom() == tile.boostzoom)) {
|
||||
// If same perspective, at same scale (tile and boost), render together
|
||||
if((hdmap.getPerspective() == tile.perspective) && (hdmap.getBoostZoom() == tile.boostzoom) && (hdmap.getTileScale() == tile.tilescale)) {
|
||||
/* If limited to one map, and this isn't it, skip */
|
||||
if((mapname != null) && (!hdmap.getName().equals(mapname)))
|
||||
continue;
|
||||
|
||||
// Maps can be set to read-only, which means they don't get re-rendered
|
||||
if (map.isReadOnly()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
shaders.add(hdmap.getShader().getStateInstance(hdmap, cache, mapiter, scale));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,15 +12,18 @@ public class HDMapTile extends MapTile {
|
|||
public final HDPerspective perspective;
|
||||
public final int tx, ty; /* Tile X and Tile Y are in tile coordinates (pixels/tile-size) */
|
||||
public final int boostzoom;
|
||||
public final int tilescale;
|
||||
|
||||
public HDMapTile(DynmapWorld world, HDPerspective perspective, int tx, int ty, int boostzoom) {
|
||||
public HDMapTile(DynmapWorld world, HDPerspective perspective, int tx, int ty, int boostzoom, int tilescale) {
|
||||
super(world);
|
||||
this.perspective = perspective;
|
||||
this.tx = tx;
|
||||
this.ty = ty;
|
||||
this.boostzoom = boostzoom;
|
||||
this.tilescale = tilescale;
|
||||
}
|
||||
|
||||
// Used for restore of saved pending renders
|
||||
public HDMapTile(DynmapWorld world, String parm) throws Exception {
|
||||
super(world);
|
||||
|
||||
|
@ -34,16 +37,22 @@ public class HDMapTile extends MapTile {
|
|||
this.boostzoom = Integer.parseInt(parms[3]);
|
||||
else
|
||||
this.boostzoom = 0;
|
||||
if (parms.length > 4) {
|
||||
this.tilescale = Integer.parseInt(parms[4]);
|
||||
}
|
||||
else {
|
||||
this.tilescale = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String saveTileData() {
|
||||
return String.format("%d,%d,%s,%d", tx, ty, perspective.getName(), boostzoom);
|
||||
return String.format("%d,%d,%s,%d,%d", tx, ty, perspective.getName(), boostzoom, tilescale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return tx ^ ty ^ perspective.hashCode() ^ world.hashCode() ^ boostzoom;
|
||||
return tx ^ ty ^ perspective.hashCode() ^ world.hashCode() ^ boostzoom ^ tilescale;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,14 +64,17 @@ public class HDMapTile extends MapTile {
|
|||
}
|
||||
|
||||
public boolean equals(HDMapTile o) {
|
||||
return o.tx == tx && o.ty == ty && (perspective == o.perspective) && (o.world == world) && (o.boostzoom == boostzoom);
|
||||
return o.tx == tx && o.ty == ty && (perspective == o.perspective) && (o.world == world) && (o.boostzoom == boostzoom) && (o.tilescale == tilescale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return world.getName() + ":" + perspective.getName() + "," + tx + "," + ty + ":" + boostzoom;
|
||||
return world.getName() + ":" + perspective.getName() + "," + tx + "," + ty + ":" + boostzoom + ":" + tilescale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSize() { return 128 << tilescale; }
|
||||
|
||||
@Override
|
||||
public boolean isBiomeDataNeeded() { return MapManager.mapman.hdmapman.isBiomeDataNeeded(this); }
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@ public interface HDPerspective {
|
|||
/* Get name of perspective */
|
||||
String getName();
|
||||
/* Get tiles invalidated by change at given location */
|
||||
List<TileFlags.TileCoord> getTileCoords(DynmapWorld w, int x, int y, int z);
|
||||
List<TileFlags.TileCoord> getTileCoords(DynmapWorld w, int x, int y, int z, int tilescale);
|
||||
/* Get tiles invalidated by change at given volume, defined by 2 opposite corner locations */
|
||||
List<TileFlags.TileCoord> getTileCoords(DynmapWorld w, int minx, int miny, int minz, int maxx, int maxy, int maxz);
|
||||
List<TileFlags.TileCoord> getTileCoords(DynmapWorld w, int minx, int miny, int minz, int maxx, int maxy, int maxz, int tilescale);
|
||||
/* Get tiles adjacent to given tile */
|
||||
MapTile[] getAdjecentTiles(MapTile tile);
|
||||
/* Get chunks needed for given tile */
|
||||
|
|
|
@ -53,6 +53,10 @@ public interface HDPerspectiveState {
|
|||
* @return y coordinate
|
||||
*/
|
||||
int getPixelY();
|
||||
/**
|
||||
* Get current patch shade setting (false = no shadows)
|
||||
*/
|
||||
boolean getShade();
|
||||
/**
|
||||
* Return submodel alpha value (-1 if no submodel rendered)
|
||||
* @return alpha value
|
||||
|
|
|
@ -8,7 +8,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.dynmap.Client;
|
||||
import org.dynmap.Color;
|
||||
|
@ -19,7 +18,6 @@ import org.dynmap.Log;
|
|||
import org.dynmap.MapManager;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.MapType;
|
||||
import org.dynmap.MapType.ImageFormat;
|
||||
import org.dynmap.MapTypeState;
|
||||
import org.dynmap.markers.impl.MarkerAPIImpl;
|
||||
import org.dynmap.renderer.DynmapBlockState;
|
||||
|
@ -28,7 +26,6 @@ import org.dynmap.renderer.RenderPatchFactory.SideVisible;
|
|||
import org.dynmap.storage.MapStorage;
|
||||
import org.dynmap.storage.MapStorageTile;
|
||||
import org.dynmap.utils.BlockStep;
|
||||
import org.dynmap.utils.DynIntHashMap;
|
||||
import org.dynmap.hdmap.TexturePack.BlockTransparency;
|
||||
import org.dynmap.utils.DynmapBufferedImage;
|
||||
import org.dynmap.utils.LightLevels;
|
||||
|
@ -47,6 +44,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
private final int hashcode;
|
||||
/* View angles */
|
||||
public final double azimuth; /* Angle in degrees from looking north (0), east (90), south (180), or west (270) */
|
||||
public final double compassazimuth; // Angle in degrees from looking north (0), east (90), for the compass (default same as azimuth)
|
||||
public final double inclination; /* Angle in degrees from horizontal (0) to vertical (90) */
|
||||
public final double maxheight;
|
||||
public final double minheight;
|
||||
|
@ -64,10 +62,6 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
/* Scale for default tiles */
|
||||
private final int basemodscale;
|
||||
|
||||
/* dimensions of a map tile */
|
||||
public static final int tileWidth = 128;
|
||||
public static final int tileHeight = 128;
|
||||
|
||||
/* Maximum and minimum inclinations */
|
||||
public static final double MAX_INCLINATION = 90.0;
|
||||
public static final double MIN_INCLINATION = 20.0;
|
||||
|
@ -129,12 +123,14 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
double patch_t[] = new double[2*HDBlockModels.getMaxPatchCount()];
|
||||
double patch_u[] = new double[2*HDBlockModels.getMaxPatchCount()];
|
||||
double patch_v[] = new double[2*HDBlockModels.getMaxPatchCount()];
|
||||
boolean patch_shade[] = new boolean[2*HDBlockModels.getMaxPatchCount()];
|
||||
BlockStep patch_step[] = new BlockStep[2*HDBlockModels.getMaxPatchCount()];
|
||||
int patch_id[] = new int[2*HDBlockModels.getMaxPatchCount()];
|
||||
int cur_patch = -1;
|
||||
double cur_patch_u;
|
||||
double cur_patch_v;
|
||||
double cur_patch_t;
|
||||
boolean cur_shade;
|
||||
|
||||
int[] subblock_xyz = new int[3];
|
||||
final MapIterator mapiter;
|
||||
|
@ -410,6 +406,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
case TOP:
|
||||
case TOPFLIP:
|
||||
case TOPFLIPV:
|
||||
case TOPFLIPHV:
|
||||
if (det < 0.000001) {
|
||||
return hitcnt;
|
||||
}
|
||||
|
@ -453,6 +450,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
patch_t[hitcnt] = t;
|
||||
patch_u[hitcnt] = u;
|
||||
patch_v[hitcnt] = v;
|
||||
patch_shade[hitcnt] = pd.shade;
|
||||
patch_id[hitcnt] = pd.textureindex;
|
||||
if(det > 0) {
|
||||
patch_step[hitcnt] = pd.step.opposite();
|
||||
|
@ -462,6 +460,10 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
else if (pd.sidevis == SideVisible.TOPFLIPV) {
|
||||
patch_v[hitcnt] = 1 - v;
|
||||
}
|
||||
else if (pd.sidevis == SideVisible.TOPFLIPHV) {
|
||||
patch_u[hitcnt] = 1 - u;
|
||||
patch_v[hitcnt] = 1 - v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (pd.sidevis == SideVisible.FLIP) {
|
||||
|
@ -515,6 +517,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
cur_patch = patch_id[best_patch]; /* Mark this as current patch */
|
||||
cur_patch_u = patch_u[best_patch];
|
||||
cur_patch_v = patch_v[best_patch];
|
||||
cur_shade = patch_shade[best_patch];
|
||||
laststep = patch_step[best_patch];
|
||||
cur_patch_t = best_t;
|
||||
// If the water patch, switch to water state and patch index
|
||||
|
@ -906,7 +909,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
* Get current texture index
|
||||
*/
|
||||
@Override
|
||||
public int getTextureIndex() {
|
||||
public final int getTextureIndex() {
|
||||
return cur_patch;
|
||||
}
|
||||
|
||||
|
@ -914,7 +917,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
* Get current U of patch intercept
|
||||
*/
|
||||
@Override
|
||||
public double getPatchU() {
|
||||
public final double getPatchU() {
|
||||
return cur_patch_u;
|
||||
}
|
||||
|
||||
|
@ -922,10 +925,19 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
* Get current V of patch intercept
|
||||
*/
|
||||
@Override
|
||||
public double getPatchV() {
|
||||
public final double getPatchV() {
|
||||
return cur_patch_v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current patch noShadow setting (true = no shadows/lighting)
|
||||
*/
|
||||
@Override
|
||||
public final boolean getShade() {
|
||||
// Shade if shade set OR not patch
|
||||
return cur_shade || (cur_patch < 0); /* If patch hit */
|
||||
}
|
||||
/**
|
||||
* Light level cache
|
||||
* @param index of light level (0-3)
|
||||
*/
|
||||
|
@ -988,10 +1000,17 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
hashcode = name.hashCode();
|
||||
}
|
||||
double az = 90.0 + configuration.getDouble("azimuth", 135.0); /* Get azimuth (default to classic kzed POV) */
|
||||
if(az >= 360.0) {
|
||||
if (az >= 360.0) {
|
||||
az = az - 360.0;
|
||||
}
|
||||
azimuth = az;
|
||||
// Get compass azimuth - default to same as true azimuth, but allows for override
|
||||
az = 90.0 + configuration.getDouble("compassazimuth", az - 90.0); /* Get azimuth (default to classic kzed POV) */
|
||||
if (az >= 360.0) {
|
||||
az = az - 360.0;
|
||||
}
|
||||
compassazimuth = az;
|
||||
|
||||
double inc;
|
||||
inc = configuration.getDouble("inclination", 60.0);
|
||||
if(inc > MAX_INCLINATION) inc = MAX_INCLINATION;
|
||||
|
@ -1031,13 +1050,14 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<TileFlags.TileCoord> getTileCoords(DynmapWorld world, int x, int y, int z) {
|
||||
public List<TileFlags.TileCoord> getTileCoords(DynmapWorld world, int x, int y, int z, int tilescale) {
|
||||
HashSet<TileFlags.TileCoord> tiles = new HashSet<TileFlags.TileCoord>();
|
||||
Vector3D block = new Vector3D();
|
||||
block.x = x;
|
||||
block.y = y;
|
||||
block.z = z;
|
||||
Vector3D corner = new Vector3D();
|
||||
int tileSize = 128 << tilescale;
|
||||
/* Loop through corners of the cube */
|
||||
for(int i = 0; i < 2; i++) {
|
||||
double inity = block.y;
|
||||
|
@ -1045,7 +1065,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
double initz = block.z;
|
||||
for(int k = 0; k < 2; k++) {
|
||||
world_to_map.transform(block, corner); /* Get map coordinate of corner */
|
||||
tiles.add(new TileFlags.TileCoord(fastFloor(corner.x/tileWidth), fastFloor(corner.y/tileHeight)));
|
||||
tiles.add(new TileFlags.TileCoord(fastFloor(corner.x/tileSize), fastFloor(corner.y/tileSize)));
|
||||
block.z += 1;
|
||||
}
|
||||
block.z = initz;
|
||||
|
@ -1058,7 +1078,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<TileFlags.TileCoord> getTileCoords(DynmapWorld world, int minx, int miny, int minz, int maxx, int maxy, int maxz) {
|
||||
public List<TileFlags.TileCoord> getTileCoords(DynmapWorld world, int minx, int miny, int minz, int maxx, int maxy, int maxz, int tilescale) {
|
||||
ArrayList<TileFlags.TileCoord> tiles = new ArrayList<TileFlags.TileCoord>();
|
||||
Vector3D blocks[] = new Vector3D[] { new Vector3D(), new Vector3D() };
|
||||
blocks[0].x = minx - 1;
|
||||
|
@ -1074,6 +1094,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
int maxtilex = Integer.MIN_VALUE;
|
||||
int mintiley = Integer.MAX_VALUE;
|
||||
int maxtiley = Integer.MIN_VALUE;
|
||||
int tileSize = 128 << tilescale;
|
||||
/* Loop through corners of the prism */
|
||||
for(int i = 0; i < 2; i++) {
|
||||
corner.x = blocks[i].x;
|
||||
|
@ -1082,8 +1103,8 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
for(int k = 0; k < 2; k++) {
|
||||
corner.z = blocks[k].z;
|
||||
world_to_map.transform(corner, tcorner); /* Get map coordinate of corner */
|
||||
int tx = fastFloor(tcorner.x/tileWidth);
|
||||
int ty = fastFloor(tcorner.y/tileWidth);
|
||||
int tx = fastFloor(tcorner.x/(tileSize << tilescale));
|
||||
int ty = fastFloor(tcorner.y/(tileSize << tilescale));
|
||||
if(mintilex > tx) mintilex = tx;
|
||||
if(maxtilex < tx) maxtilex = tx;
|
||||
if(mintiley > ty) mintiley = ty;
|
||||
|
@ -1107,14 +1128,14 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
int x = t.tx;
|
||||
int y = t.ty;
|
||||
return new MapTile[] {
|
||||
new HDMapTile(w, this, x - 1, y - 1, t.boostzoom),
|
||||
new HDMapTile(w, this, x + 1, y - 1, t.boostzoom),
|
||||
new HDMapTile(w, this, x - 1, y + 1, t.boostzoom),
|
||||
new HDMapTile(w, this, x + 1, y + 1, t.boostzoom),
|
||||
new HDMapTile(w, this, x, y - 1, t.boostzoom),
|
||||
new HDMapTile(w, this, x + 1, y, t.boostzoom),
|
||||
new HDMapTile(w, this, x, y + 1, t.boostzoom),
|
||||
new HDMapTile(w, this, x - 1, y, t.boostzoom) };
|
||||
new HDMapTile(w, this, x - 1, y - 1, t.boostzoom, t.tilescale),
|
||||
new HDMapTile(w, this, x + 1, y - 1, t.boostzoom, t.tilescale),
|
||||
new HDMapTile(w, this, x - 1, y + 1, t.boostzoom, t.tilescale),
|
||||
new HDMapTile(w, this, x + 1, y + 1, t.boostzoom, t.tilescale),
|
||||
new HDMapTile(w, this, x, y - 1, t.boostzoom, t.tilescale),
|
||||
new HDMapTile(w, this, x + 1, y, t.boostzoom, t.tilescale),
|
||||
new HDMapTile(w, this, x, y + 1, t.boostzoom, t.tilescale),
|
||||
new HDMapTile(w, this, x - 1, y, t.boostzoom, t.tilescale) };
|
||||
}
|
||||
|
||||
private static final int corners_by_side[][] = {
|
||||
|
@ -1136,6 +1157,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
int max_chunk_x = Integer.MIN_VALUE;
|
||||
int min_chunk_z = Integer.MAX_VALUE;
|
||||
int max_chunk_z = Integer.MIN_VALUE;
|
||||
int tileSize = tile.getTileSize();
|
||||
|
||||
/* Make corners for volume:
|
||||
* 0 = bottom-lower-left (xyz),
|
||||
|
@ -1153,8 +1175,8 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
for(int y = t.ty; y <= (t.ty+1); y++) {
|
||||
for(int z = 0; z <= 1; z++) {
|
||||
corners[idx] = new Vector3D();
|
||||
corners[idx].x = x*tileWidth + dx;
|
||||
corners[idx].y = y*tileHeight + dy;
|
||||
corners[idx].x = x*tileSize + dx;
|
||||
corners[idx].y = y*tileSize + dy;
|
||||
corners[idx].z = (z == 1) ? t.getDynmapWorld().worldheight : t.getDynmapWorld().minY;
|
||||
map_to_world.transform(corners[idx]);
|
||||
/* Compute chunk coordinates of corner */
|
||||
|
@ -1208,8 +1230,9 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
Color rslt = new Color();
|
||||
MapIterator mapiter = cache.getIterator(0, 0, 0);
|
||||
DynmapWorld world = tile.getDynmapWorld();
|
||||
int tileSize = tile.getTileSize();
|
||||
int scaled = 0;
|
||||
if ((tile.boostzoom > 0) && MarkerAPIImpl.testTileForBoostMarkers(cache.getWorld(), this, tile.tx * tileWidth, tile.ty * tileHeight, tileWidth)) {
|
||||
if ((tile.boostzoom > 0) && MarkerAPIImpl.testTileForBoostMarkers(cache.getWorld(), this, tile.tx * tileSize, tile.ty * tileSize, tileSize)) {
|
||||
scaled = tile.boostzoom;
|
||||
}
|
||||
int sizescale = 1 << scaled;
|
||||
|
@ -1226,26 +1249,26 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
DynmapBufferedImage dayim[] = new DynmapBufferedImage[numshaders];
|
||||
int[][] argb_buf = new int[numshaders][];
|
||||
int[][] day_argb_buf = new int[numshaders][];
|
||||
boolean isjpg[] = new boolean[numshaders];
|
||||
boolean isOpaque[] = new boolean[numshaders];
|
||||
int bgday[] = new int[numshaders];
|
||||
int bgnight[] = new int[numshaders];
|
||||
|
||||
for(int i = 0; i < numshaders; i++) {
|
||||
HDLighting lighting = shaderstate[i].getLighting();
|
||||
im[i] = DynmapBufferedImage.allocateBufferedImage(tileWidth * sizescale, tileHeight * sizescale);
|
||||
im[i] = DynmapBufferedImage.allocateBufferedImage(tileSize * sizescale, tileSize * sizescale);
|
||||
argb_buf[i] = im[i].argb_buf;
|
||||
if(lighting.isNightAndDayEnabled()) {
|
||||
dayim[i] = DynmapBufferedImage.allocateBufferedImage(tileWidth * sizescale, tileHeight * sizescale);
|
||||
dayim[i] = DynmapBufferedImage.allocateBufferedImage(tileSize * sizescale, tileSize * sizescale);
|
||||
day_argb_buf[i] = dayim[i].argb_buf;
|
||||
}
|
||||
isjpg[i] = shaderstate[i].getMap().getImageFormat() != ImageFormat.FORMAT_PNG;
|
||||
isOpaque[i] = !shaderstate[i].getMap().getImageFormat().getEncoding().hasAlpha;
|
||||
bgday[i] = shaderstate[i].getMap().getBackgroundARGBDay();
|
||||
bgnight[i] = shaderstate[i].getMap().getBackgroundARGBNight();
|
||||
}
|
||||
// Mark the tiles we're going to render as validated
|
||||
for (int i = 0; i < numshaders; i++) {
|
||||
MapTypeState mts = world.getMapState(shaderstate[i].getMap());
|
||||
if (mts != null) {
|
||||
if (mts != null && mts.type.isReadOnly() == false) {
|
||||
mts.validateTile(tile.tx, tile.ty);
|
||||
}
|
||||
}
|
||||
|
@ -1255,8 +1278,8 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
ps.top = new Vector3D();
|
||||
ps.bottom = new Vector3D();
|
||||
ps.direction = new Vector3D();
|
||||
double xbase = tile.tx * tileWidth;
|
||||
double ybase = tile.ty * tileHeight;
|
||||
double xbase = tile.tx * tileSize;
|
||||
double ybase = tile.ty * tileSize;
|
||||
boolean shaderdone[] = new boolean[numshaders];
|
||||
boolean rendered[] = new boolean[numshaders];
|
||||
double height = maxheight;
|
||||
|
@ -1271,9 +1294,9 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
miny = tile.getDynmapWorld().minY;
|
||||
}
|
||||
|
||||
for(int x = 0; x < tileWidth * sizescale; x++) {
|
||||
for(int x = 0; x < tileSize * sizescale; x++) {
|
||||
ps.px = x;
|
||||
for(int y = 0; y < tileHeight * sizescale; y++) {
|
||||
for(int y = 0; y < tileSize * sizescale; y++) {
|
||||
ps.top.x = ps.bottom.x = xbase + (x + 0.5) / sizescale; /* Start at center of pixel at Y=height+0.5, bottom at Y=-0.5 */
|
||||
ps.top.y = ps.bottom.y = ybase + (y + 0.5) / sizescale;
|
||||
ps.top.z = height + 0.5; ps.bottom.z = miny - 0.5;
|
||||
|
@ -1301,21 +1324,21 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
}
|
||||
shaderstate[i].getRayColor(rslt, 0);
|
||||
int c_argb = rslt.getARGB();
|
||||
if(c_argb != 0) rendered[i] = true;
|
||||
if(isjpg[i] && (c_argb == 0)) {
|
||||
argb_buf[i][(tileHeight*sizescale-y-1)*tileWidth*sizescale + x] = bgnight[i];
|
||||
if (c_argb != 0) rendered[i] = true;
|
||||
if (isOpaque[i] && (c_argb == 0)) {
|
||||
argb_buf[i][(tileSize*sizescale-y-1)*tileSize*sizescale + x] = bgnight[i];
|
||||
}
|
||||
else {
|
||||
argb_buf[i][(tileHeight*sizescale-y-1)*tileWidth*sizescale + x] = c_argb;
|
||||
argb_buf[i][(tileSize*sizescale-y-1)*tileSize*sizescale + x] = c_argb;
|
||||
}
|
||||
if(day_argb_buf[i] != null) {
|
||||
if (day_argb_buf[i] != null) {
|
||||
shaderstate[i].getRayColor(rslt, 1);
|
||||
c_argb = rslt.getARGB();
|
||||
if(isjpg[i] && (c_argb == 0)) {
|
||||
day_argb_buf[i][(tileHeight*sizescale-y-1)*tileWidth*sizescale + x] = bgday[i];
|
||||
if (isOpaque[i] && (c_argb == 0)) {
|
||||
day_argb_buf[i][(tileSize*sizescale-y-1)*tileSize*sizescale + x] = bgday[i];
|
||||
}
|
||||
else {
|
||||
day_argb_buf[i][(tileHeight*sizescale-y-1)*tileWidth*sizescale + x] = c_argb;
|
||||
day_argb_buf[i][(tileSize*sizescale-y-1)*tileSize*sizescale + x] = c_argb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1436,7 +1459,7 @@ public class IsoHDPerspective implements HDPerspective {
|
|||
s(mapObject, "scale", basemodscale);
|
||||
s(mapObject, "worldtomap", world_to_map.toJSON());
|
||||
s(mapObject, "maptoworld", map_to_world.toJSON());
|
||||
int dir = (((360 + (int)(22.5+azimuth)) / 45) + 6) % 8;
|
||||
int dir = (((360 + (int)(22.5+compassazimuth)) / 45) + 6) % 8;
|
||||
s(mapObject, "compassview", directions[dir]);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,7 @@ import org.dynmap.Color;
|
|||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.DynmapCore;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.utils.LightLevels;
|
||||
import org.dynmap.utils.BlockStep;
|
||||
|
||||
public class LightLevelHDLighting extends DefaultHDLighting {
|
||||
private final Color[] lightlevelcolors = new Color[16];
|
||||
|
|
|
@ -4,7 +4,6 @@ import org.dynmap.Color;
|
|||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.DynmapCore;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.utils.LightLevels;
|
||||
import org.dynmap.utils.BlockStep;
|
||||
|
@ -218,8 +217,8 @@ public class ShadowHDLighting extends DefaultHDLighting {
|
|||
|
||||
/* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */
|
||||
public void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor) {
|
||||
int[] shadowscale = null;
|
||||
if(smooth) {
|
||||
int[] shadowscale = null;
|
||||
if (smooth && ps.getShade()) {
|
||||
shadowscale = ss.getLightingTable();
|
||||
if (shadowscale == null) {
|
||||
shadowscale = defLightingTable;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.dynmap.hdmap;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -1254,8 +1255,13 @@ public class TexturePack {
|
|||
/* Load image */
|
||||
if(is != null) {
|
||||
ImageIO.setUseCache(false);
|
||||
img = ImageIO.read(is);
|
||||
if(img == null) { throw new FileNotFoundException(); }
|
||||
try {
|
||||
img = ImageIO.read(is);
|
||||
} catch (IOException iox) {
|
||||
}
|
||||
if (img == null) {
|
||||
Log.warning(String.format("Error loading image %s from module %s", fname, modid));
|
||||
}
|
||||
}
|
||||
if(idx >= imgs.length) {
|
||||
LoadedImage[] newimgs = new LoadedImage[idx+1];
|
||||
|
@ -1267,7 +1273,17 @@ public class TexturePack {
|
|||
imgs[idx].width = img.getWidth();
|
||||
imgs[idx].height = img.getHeight();
|
||||
imgs[idx].argb = new int[imgs[idx].width * imgs[idx].height];
|
||||
img.getRGB(0, 0, imgs[idx].width, imgs[idx].height, imgs[idx].argb, 0, imgs[idx].width);
|
||||
if (img.getType() == BufferedImage.TYPE_BYTE_GRAY) { // We don't want alpha correction, apparently
|
||||
float[] buffer = new float[imgs[idx].width * imgs[idx].height];
|
||||
img.getData().getPixels(0, 0, imgs[idx].width, imgs[idx].height, buffer);
|
||||
for (int i = 0; i < imgs[idx].argb.length; i++) {
|
||||
int v = (int) buffer[i];
|
||||
imgs[idx].argb[i] = 0xFF000000 | (v << 16) | (v << 8) | v;
|
||||
}
|
||||
}
|
||||
else {
|
||||
img.getRGB(0, 0, imgs[idx].width, imgs[idx].height, imgs[idx].argb, 0, imgs[idx].width);
|
||||
}
|
||||
img.flush();
|
||||
imgs[idx].isLoaded = true;
|
||||
}
|
||||
|
@ -1818,7 +1834,7 @@ public class TexturePack {
|
|||
|
||||
try {
|
||||
String line;
|
||||
rdr = new LineNumberReader(new InputStreamReader(txtfile));
|
||||
rdr = new LineNumberReader(new BufferedReader(new InputStreamReader(txtfile)));
|
||||
while((line = rdr.readLine()) != null) {
|
||||
if(line.startsWith("#")) {
|
||||
}
|
||||
|
@ -1917,7 +1933,7 @@ public class TexturePack {
|
|||
Map<DynmapBlockState, BitSet> bsprslt;
|
||||
try {
|
||||
String line;
|
||||
rdr = new LineNumberReader(new InputStreamReader(txtfile));
|
||||
rdr = new LineNumberReader(new BufferedReader(new InputStreamReader(txtfile)));
|
||||
while((line = rdr.readLine()) != null) {
|
||||
boolean skip = false;
|
||||
int lineNum = rdr.getLineNumber();
|
||||
|
@ -2097,7 +2113,7 @@ public class TexturePack {
|
|||
else if(av[0].equals("custColorMult")) {
|
||||
try {
|
||||
Class<?> cls = Class.forName(av[1]);
|
||||
custColorMult = (CustomColorMultiplier)cls.newInstance();
|
||||
custColorMult = (CustomColorMultiplier)cls.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Error loading custom color multiplier - " + av[1] + ": " + x.getMessage());
|
||||
}
|
||||
|
@ -2263,7 +2279,7 @@ public class TexturePack {
|
|||
else if(av[0].equals("custColorMult")) {
|
||||
try {
|
||||
Class<?> cls = Class.forName(av[1]);
|
||||
custColorMult = (CustomColorMultiplier)cls.newInstance();
|
||||
custColorMult = (CustomColorMultiplier)cls.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Error loading custom color multiplier - " + av[1] + ": " + x.getMessage());
|
||||
}
|
||||
|
@ -2542,7 +2558,11 @@ public class TexturePack {
|
|||
else {
|
||||
faceindex = laststep.ordinal();
|
||||
}
|
||||
textid = map.faces[faceindex];
|
||||
try {
|
||||
textid = map.faces[faceindex];
|
||||
} catch (ArrayIndexOutOfBoundsException aioob) {
|
||||
textid = -1;
|
||||
}
|
||||
if (ctm != null) {
|
||||
int mod = 0;
|
||||
if(textid >= COLORMOD_MULT_INTERNAL) {
|
||||
|
|
|
@ -202,50 +202,52 @@ public class TexturePackHDShader implements HDShader {
|
|||
|
||||
if (c.getAlpha() > 0) {
|
||||
/* Scale brightness depending upon face */
|
||||
if (this.lightingTable != null) {
|
||||
switch(ps.getLastBlockStep()) {
|
||||
case X_MINUS:
|
||||
case X_PLUS:
|
||||
/* 60% brightness */
|
||||
c.blendColor(0xFF999999);
|
||||
break;
|
||||
case Y_MINUS:
|
||||
// 95% for even
|
||||
if((mapiter.getY() & 0x01) == 0) {
|
||||
c.blendColor(0xFFF3F3F3);
|
||||
}
|
||||
break;
|
||||
case Y_PLUS:
|
||||
/* 50%*/
|
||||
c.blendColor(0xFF808080);
|
||||
break;
|
||||
case Z_MINUS:
|
||||
case Z_PLUS:
|
||||
default:
|
||||
/* 80%*/
|
||||
c.blendColor(0xFFCDCDCD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch(ps.getLastBlockStep()) {
|
||||
case X_MINUS:
|
||||
case X_PLUS:
|
||||
/* 60% brightness */
|
||||
c.blendColor(0xFFA0A0A0);
|
||||
break;
|
||||
case Y_MINUS:
|
||||
case Y_PLUS:
|
||||
/* 85% brightness for even, 90% for even*/
|
||||
if((mapiter.getY() & 0x01) == 0)
|
||||
c.blendColor(0xFFD9D9D9);
|
||||
else
|
||||
c.blendColor(0xFFE6E6E6);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ps.getShade()) {
|
||||
if (this.lightingTable != null) {
|
||||
switch (ps.getLastBlockStep()) {
|
||||
case X_MINUS:
|
||||
case X_PLUS:
|
||||
/* 60% brightness */
|
||||
c.blendColor(0xFF999999);
|
||||
break;
|
||||
case Y_MINUS:
|
||||
// 95% for even
|
||||
if((mapiter.getY() & 0x01) == 0) {
|
||||
c.blendColor(0xFFF3F3F3);
|
||||
}
|
||||
break;
|
||||
case Y_PLUS:
|
||||
/* 50%*/
|
||||
c.blendColor(0xFF808080);
|
||||
break;
|
||||
case Z_MINUS:
|
||||
case Z_PLUS:
|
||||
default:
|
||||
/* 80%*/
|
||||
c.blendColor(0xFFCDCDCD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (ps.getLastBlockStep()) {
|
||||
case X_MINUS:
|
||||
case X_PLUS:
|
||||
/* 60% brightness */
|
||||
c.blendColor(0xFFA0A0A0);
|
||||
break;
|
||||
case Y_MINUS:
|
||||
case Y_PLUS:
|
||||
/* 85% brightness for even, 90% for even*/
|
||||
if((mapiter.getY() & 0x01) == 0)
|
||||
c.blendColor(0xFFD9D9D9);
|
||||
else
|
||||
c.blendColor(0xFFE6E6E6);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Handle light level, if needed */
|
||||
lighting.applyLighting(ps, this, c, tmpcolor);
|
||||
/* If grid scale, add it */
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.dynmap.hdmap;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -61,13 +62,13 @@ public class TexturePackLoader {
|
|||
if (zf != null) {
|
||||
ZipEntry ze = zf.getEntry(rname);
|
||||
if ((ze != null) && (!ze.isDirectory())) {
|
||||
return zf.getInputStream(ze);
|
||||
return new BufferedInputStream(zf.getInputStream(ze));
|
||||
}
|
||||
}
|
||||
else if (tpdir != null) {
|
||||
File f = new File(tpdir, rname);
|
||||
if (f.isFile() && f.canRead()) {
|
||||
return new FileInputStream(f);
|
||||
return new BufferedInputStream(new FileInputStream(f));
|
||||
}
|
||||
}
|
||||
} catch (IOException iox) {
|
||||
|
@ -75,7 +76,7 @@ public class TexturePackLoader {
|
|||
// Fall through - load as resource from mod, if possible, or from jar
|
||||
InputStream is = dsi.openResource(modname, rname);
|
||||
if (is != null) {
|
||||
return is;
|
||||
return new BufferedInputStream(is);
|
||||
}
|
||||
if (modname != null) {
|
||||
ModSource ms = src_by_mod.get(modname);
|
||||
|
@ -118,7 +119,7 @@ public class TexturePackLoader {
|
|||
Log.warning("Resource " + rname + " for mod " + modname + " not found");
|
||||
}
|
||||
|
||||
return is;
|
||||
return (is != null) ? new BufferedInputStream(is) : null;
|
||||
}
|
||||
public void close() {
|
||||
if(zf != null) {
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
package org.dynmap.hdmap.renderer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dynmap.renderer.CustomRenderer;
|
||||
import org.dynmap.renderer.DynmapBlockState;
|
||||
import org.dynmap.renderer.MapDataContext;
|
||||
import org.dynmap.renderer.RenderPatch;
|
||||
import org.dynmap.renderer.RenderPatchFactory;
|
||||
|
||||
/**
|
||||
* Simple renderer for handling single and double chests (1.13+)
|
||||
|
|
|
@ -5,7 +5,6 @@ import java.util.BitSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.renderer.CustomRenderer;
|
||||
import org.dynmap.renderer.MapDataContext;
|
||||
import org.dynmap.renderer.RenderPatch;
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import org.dynmap.Client;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.hdmap.HDPerspective;
|
||||
import org.dynmap.markers.AreaMarker;
|
||||
|
@ -73,9 +72,9 @@ class AreaMarkerImpl implements AreaMarker, EnterExitMarker {
|
|||
AreaMarkerImpl(String id, String lbl, boolean markup, String world, double x[], double z[], boolean persistent, MarkerSetImpl set) {
|
||||
markerid = id;
|
||||
if(lbl != null)
|
||||
label = markup ? lbl : Client.encodeForHTML(lbl);
|
||||
label = markup ? Client.sanitizeHTML(lbl) : Client.encodeForHTML(lbl);
|
||||
else
|
||||
label = markup ? id : Client.encodeForHTML(id);
|
||||
label = markup ? Client.sanitizeHTML(id) : Client.encodeForHTML(id);
|
||||
this.markup = markup;
|
||||
this.corners = new ArrayList<Coord>();
|
||||
for(int i = 0; i < x.length; i++) {
|
||||
|
@ -119,9 +118,10 @@ class AreaMarkerImpl implements AreaMarker, EnterExitMarker {
|
|||
* Load marker from configuration node
|
||||
* @param node - configuration node
|
||||
*/
|
||||
boolean loadPersistentData(ConfigurationNode node) {
|
||||
boolean loadPersistentData(ConfigurationNode node, boolean isSafe) {
|
||||
markup = node.getBoolean("markup", false);
|
||||
label = MarkerAPIImpl.escapeForHTMLIfNeeded(node.getString("label", markerid), markup);
|
||||
if (!isSafe) label = Client.sanitizeHTML(label);
|
||||
ytop = node.getDouble("ytop", 64.0);
|
||||
ybottom = node.getDouble("ybottom", 64.0);
|
||||
List<Double> xx = node.getList("x");
|
||||
|
@ -134,6 +134,7 @@ class AreaMarkerImpl implements AreaMarker, EnterExitMarker {
|
|||
world = node.getString("world", "world");
|
||||
normalized_world = DynmapWorld.normalizeWorldName(world);
|
||||
desc = node.getString("desc", null);
|
||||
if (!isSafe) desc = Client.sanitizeHTML(desc);
|
||||
lineweight = node.getInteger("strokeWeight", -1);
|
||||
if(lineweight == -1) { /* Handle typo-saved value */
|
||||
lineweight = node.getInteger("stokeWeight", 3);
|
||||
|
@ -216,12 +217,7 @@ class AreaMarkerImpl implements AreaMarker, EnterExitMarker {
|
|||
@Override
|
||||
public void setLabel(String lbl, boolean markup) {
|
||||
if(markerset == null) return;
|
||||
if (markup) {
|
||||
label = lbl;
|
||||
}
|
||||
else { // If not markup, escape any HTML-active characters (<>&"')
|
||||
label = Client.encodeForHTML(lbl);
|
||||
}
|
||||
label = markup ? Client.sanitizeHTML(lbl) : Client.encodeForHTML(lbl);
|
||||
this.markup = markup;
|
||||
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
|
||||
if(ispersistent)
|
||||
|
@ -299,6 +295,7 @@ class AreaMarkerImpl implements AreaMarker, EnterExitMarker {
|
|||
@Override
|
||||
public void setDescription(String desc) {
|
||||
if(markerset == null) return;
|
||||
desc = Client.sanitizeHTML(desc);
|
||||
if((this.desc == null) || (this.desc.equals(desc) == false)) {
|
||||
this.desc = desc;
|
||||
MarkerAPIImpl.areaMarkerUpdated(this, MarkerUpdate.UPDATED);
|
||||
|
|
|
@ -11,7 +11,6 @@ import org.dynmap.hdmap.HDPerspective;
|
|||
import org.dynmap.markers.CircleMarker;
|
||||
import org.dynmap.markers.EnterExitMarker;
|
||||
import org.dynmap.markers.MarkerSet;
|
||||
import org.dynmap.markers.EnterExitMarker.EnterExitText;
|
||||
import org.dynmap.markers.impl.MarkerAPIImpl.MarkerUpdate;
|
||||
import org.dynmap.utils.Vector3D;
|
||||
|
||||
|
@ -68,6 +67,7 @@ class CircleMarkerImpl implements CircleMarker, EnterExitMarker {
|
|||
label = markup ? lbl : Client.encodeColorInHTML(lbl);
|
||||
else
|
||||
label = markup ? id : Client.encodeColorInHTML(id);
|
||||
label = Client.sanitizeHTML(label);
|
||||
this.markup = markup;
|
||||
this.x = x; this.y = y; this.z = z;
|
||||
this.xr = xr; this.zr = zr;
|
||||
|
@ -87,7 +87,7 @@ class CircleMarkerImpl implements CircleMarker, EnterExitMarker {
|
|||
CircleMarkerImpl(String id, MarkerSetImpl set) {
|
||||
markerid = id;
|
||||
markerset = set;
|
||||
label = Client.encodeForHTML(id);
|
||||
label = Client.sanitizeHTML(Client.encodeForHTML(id));
|
||||
markup = false;
|
||||
desc = null;
|
||||
world = normalized_world = "world";
|
||||
|
@ -101,9 +101,10 @@ class CircleMarkerImpl implements CircleMarker, EnterExitMarker {
|
|||
* Load marker from configuration node
|
||||
* @param node - configuration node
|
||||
*/
|
||||
boolean loadPersistentData(ConfigurationNode node) {
|
||||
boolean loadPersistentData(ConfigurationNode node, boolean isSafe) {
|
||||
markup = node.getBoolean("markup", false);
|
||||
label = MarkerAPIImpl.escapeForHTMLIfNeeded(node.getString("label", markerid), markup);
|
||||
if (!isSafe) label = Client.sanitizeHTML(label);
|
||||
world = node.getString("world", "world");
|
||||
normalized_world = DynmapWorld.normalizeWorldName(world);
|
||||
x = node.getDouble("x", 0);
|
||||
|
@ -112,6 +113,7 @@ class CircleMarkerImpl implements CircleMarker, EnterExitMarker {
|
|||
xr = node.getDouble("xr", 0);
|
||||
zr = node.getDouble("zr", 0);
|
||||
desc = node.getString("desc", null);
|
||||
if (!isSafe) desc = Client.sanitizeHTML(desc);
|
||||
lineweight = node.getInteger("strokeWeight", -1);
|
||||
if(lineweight == -1) { /* Handle typo-saved value */
|
||||
lineweight = node.getInteger("stokeWeight", 3);
|
||||
|
@ -193,6 +195,7 @@ class CircleMarkerImpl implements CircleMarker, EnterExitMarker {
|
|||
@Override
|
||||
public void setLabel(String lbl, boolean markup) {
|
||||
label = markup ? lbl : Client.encodeForHTML(lbl);
|
||||
label = Client.sanitizeHTML(label);
|
||||
this.markup = markup;
|
||||
MarkerAPIImpl.circleMarkerUpdated(this, MarkerUpdate.UPDATED);
|
||||
if(ispersistent)
|
||||
|
@ -263,6 +266,7 @@ class CircleMarkerImpl implements CircleMarker, EnterExitMarker {
|
|||
}
|
||||
@Override
|
||||
public void setDescription(String desc) {
|
||||
desc = Client.sanitizeHTML(desc);
|
||||
if((this.desc == null) || (this.desc.equals(desc) == false)) {
|
||||
this.desc = desc;
|
||||
MarkerAPIImpl.circleMarkerUpdated(this, MarkerUpdate.UPDATED);
|
||||
|
|
|
@ -102,14 +102,14 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
|
||||
public MarkerUpdated(Marker m, boolean deleted) {
|
||||
this.id = m.getMarkerID();
|
||||
this.label = Client.sanitizeHTML(m.getLabel());
|
||||
this.label = m.getLabel();
|
||||
this.x = m.getX();
|
||||
this.y = m.getY();
|
||||
this.z = m.getZ();
|
||||
this.set = m.getMarkerSet().getMarkerSetID();
|
||||
this.icon = m.getMarkerIcon().getMarkerIconID();
|
||||
this.markup = true; // We are markup format all the time now
|
||||
this.desc = Client.sanitizeHTML(m.getDescription());
|
||||
this.desc = m.getDescription();
|
||||
this.dim = m.getMarkerIcon().getMarkerIconSize().getSize();
|
||||
this.minzoom = m.getMinZoom();
|
||||
this.maxzoom = m.getMaxZoom();
|
||||
|
@ -153,7 +153,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
|
||||
public AreaMarkerUpdated(AreaMarker m, boolean deleted) {
|
||||
this.id = m.getMarkerID();
|
||||
this.label = Client.sanitizeHTML(m.getLabel());
|
||||
this.label = m.getLabel();
|
||||
this.ytop = m.getTopY();
|
||||
this.ybottom = m.getBottomY();
|
||||
int cnt = m.getCornerCount();
|
||||
|
@ -168,7 +168,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
opacity = m.getLineOpacity();
|
||||
fillcolor = String.format("#%06X", m.getFillColor());
|
||||
fillopacity = m.getFillOpacity();
|
||||
desc = Client.sanitizeHTML(m.getDescription());
|
||||
desc = m.getDescription();
|
||||
this.minzoom = m.getMinZoom();
|
||||
this.maxzoom = m.getMaxZoom();
|
||||
this.markup = true; // We are markup format all the time now
|
||||
|
@ -211,7 +211,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
|
||||
public PolyLineMarkerUpdated(PolyLineMarker m, boolean deleted) {
|
||||
this.id = m.getMarkerID();
|
||||
this.label = Client.sanitizeHTML(m.getLabel());
|
||||
this.label = m.getLabel();
|
||||
this.markup = true; // We are markup format all the time now
|
||||
int cnt = m.getCornerCount();
|
||||
x = new double[cnt];
|
||||
|
@ -225,7 +225,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
color = String.format("#%06X", m.getLineColor());
|
||||
weight = m.getLineWeight();
|
||||
opacity = m.getLineOpacity();
|
||||
desc = Client.sanitizeHTML(m.getDescription());
|
||||
desc = m.getDescription();
|
||||
this.minzoom = m.getMinZoom();
|
||||
this.maxzoom = m.getMaxZoom();
|
||||
|
||||
|
@ -271,7 +271,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
|
||||
public CircleMarkerUpdated(CircleMarker m, boolean deleted) {
|
||||
this.id = m.getMarkerID();
|
||||
this.label = Client.sanitizeHTML(m.getLabel());
|
||||
this.label = m.getLabel();
|
||||
this.x = m.getCenterX();
|
||||
this.y = m.getCenterY();
|
||||
this.z = m.getCenterZ();
|
||||
|
@ -283,7 +283,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
opacity = m.getLineOpacity();
|
||||
fillcolor = String.format("#%06X", m.getFillColor());
|
||||
fillopacity = m.getFillOpacity();
|
||||
desc = Client.sanitizeHTML(m.getDescription());
|
||||
desc = m.getDescription();
|
||||
this.minzoom = m.getMinZoom();
|
||||
this.maxzoom = m.getMaxZoom();
|
||||
|
||||
|
@ -342,7 +342,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
}
|
||||
|
||||
private boolean stop = false;
|
||||
private Set<String> dirty_worlds = new HashSet<String>();
|
||||
private ConcurrentHashMap<String, String> dirty_worlds = new ConcurrentHashMap<String, String>();
|
||||
private boolean dirty_markers = false;
|
||||
|
||||
private class DoFileWrites implements Runnable {
|
||||
|
@ -350,18 +350,19 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
if(stop)
|
||||
return;
|
||||
lock.readLock().lock();
|
||||
Set<String> dirty = new HashSet<String>(dirty_worlds.keySet());
|
||||
dirty_worlds.clear();
|
||||
try {
|
||||
/* Write markers first - drives JSON updates too */
|
||||
if(dirty_markers) {
|
||||
if (dirty_markers) {
|
||||
doSaveMarkers();
|
||||
dirty_markers = false;
|
||||
}
|
||||
/* Process any dirty worlds */
|
||||
if(!dirty_worlds.isEmpty()) {
|
||||
for(String world : dirty_worlds) {
|
||||
if (!dirty.isEmpty()) {
|
||||
for(String world : dirty) {
|
||||
writeMarkersFile(world);
|
||||
}
|
||||
dirty_worlds.clear();
|
||||
}
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
|
@ -821,6 +822,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
final ConfigurationNode conf = new ConfigurationNode(api.markerpersist); /* Make configuration object */
|
||||
/* First, save icon definitions */
|
||||
HashMap<String, Object> icons = new HashMap<String,Object>();
|
||||
conf.put("isSafe", true); // Mark as safe (sanitized)
|
||||
for(String id : api.markericons.keySet()) {
|
||||
MarkerIconImpl ico = api.markericons.get(id);
|
||||
Map<String,Object> dat = ico.getPersistentData();
|
||||
|
@ -872,7 +874,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
private void freshenMarkerFiles() {
|
||||
if(MapManager.mapman != null) {
|
||||
for(DynmapWorld w : MapManager.mapman.worlds) {
|
||||
dirty_worlds.add(w.getName());
|
||||
dirty_worlds.put(w.getName(),"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -884,13 +886,14 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
ConfigurationNode conf = new ConfigurationNode(api.markerpersist); /* Make configuration object */
|
||||
conf.load(); /* Load persistence */
|
||||
lock.writeLock().lock();
|
||||
boolean isSafe = conf.getBoolean("isSafe", false);
|
||||
try {
|
||||
/* Get icons */
|
||||
ConfigurationNode icons = conf.getNode("icons");
|
||||
if(icons == null) return false;
|
||||
for(String id : icons.keySet()) {
|
||||
MarkerIconImpl ico = new MarkerIconImpl(id);
|
||||
if(ico.loadPersistentData(icons.getNode(id))) {
|
||||
if(ico.loadPersistentData(icons.getNode(id), isSafe)) {
|
||||
markericons.put(id, ico);
|
||||
}
|
||||
}
|
||||
|
@ -899,7 +902,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
if(sets != null) {
|
||||
for(String id: sets.keySet()) {
|
||||
MarkerSetImpl set = new MarkerSetImpl(id);
|
||||
if(set.loadPersistentData(sets.getNode(id))) {
|
||||
if(set.loadPersistentData(sets.getNode(id), isSafe)) {
|
||||
markersets.put(id, set);
|
||||
}
|
||||
}
|
||||
|
@ -909,7 +912,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
if(psets != null) {
|
||||
for(String id: psets.keySet()) {
|
||||
PlayerSetImpl set = new PlayerSetImpl(id);
|
||||
if(set.loadPersistentData(sets.getNode(id))) {
|
||||
if(set.loadPersistentData(sets.getNode(id), isSafe)) {
|
||||
playersets.put(id, set);
|
||||
}
|
||||
}
|
||||
|
@ -931,7 +934,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
static void markerUpdated(MarkerImpl marker, MarkerUpdate update) {
|
||||
/* Freshen marker file for the world for this marker */
|
||||
if(api != null)
|
||||
api.dirty_worlds.add(marker.getNormalizedWorld());
|
||||
api.dirty_worlds.put(marker.getNormalizedWorld(),"");
|
||||
/* Enqueue client update */
|
||||
if(MapManager.mapman != null)
|
||||
MapManager.mapman.pushUpdate(marker.getNormalizedWorld(), new MarkerUpdated(marker, update == MarkerUpdate.DELETED));
|
||||
|
@ -944,7 +947,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
static void areaMarkerUpdated(AreaMarkerImpl marker, MarkerUpdate update) {
|
||||
/* Freshen marker file for the world for this marker */
|
||||
if(api != null)
|
||||
api.dirty_worlds.add(marker.getNormalizedWorld());
|
||||
api.dirty_worlds.put(marker.getNormalizedWorld(),"");
|
||||
/* Enqueue client update */
|
||||
if(MapManager.mapman != null)
|
||||
MapManager.mapman.pushUpdate(marker.getNormalizedWorld(), new AreaMarkerUpdated(marker, update == MarkerUpdate.DELETED));
|
||||
|
@ -957,7 +960,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
static void polyLineMarkerUpdated(PolyLineMarkerImpl marker, MarkerUpdate update) {
|
||||
/* Freshen marker file for the world for this marker */
|
||||
if(api != null)
|
||||
api.dirty_worlds.add(marker.getNormalizedWorld());
|
||||
api.dirty_worlds.put(marker.getNormalizedWorld(),"");
|
||||
/* Enqueue client update */
|
||||
if(MapManager.mapman != null)
|
||||
MapManager.mapman.pushUpdate(marker.getNormalizedWorld(), new PolyLineMarkerUpdated(marker, update == MarkerUpdate.DELETED));
|
||||
|
@ -970,7 +973,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
static void circleMarkerUpdated(CircleMarkerImpl marker, MarkerUpdate update) {
|
||||
/* Freshen marker file for the world for this marker */
|
||||
if(api != null)
|
||||
api.dirty_worlds.add(marker.getNormalizedWorld());
|
||||
api.dirty_worlds.put(marker.getNormalizedWorld(),"");
|
||||
/* Enqueue client update */
|
||||
if(MapManager.mapman != null)
|
||||
MapManager.mapman.pushUpdate(marker.getNormalizedWorld(), new CircleMarkerUpdated(marker, update == MarkerUpdate.DELETED));
|
||||
|
@ -2173,6 +2176,10 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
sender.sendMessage("file:\"filename\" required");
|
||||
return true;
|
||||
}
|
||||
if (!validateImportFile(file)) {
|
||||
sender.sendMessage("Error: '" + ARG_FILE + "' cannot include directory separators - must be just filename in " + plugin.getImportFolder().getAbsolutePath() + " directory");
|
||||
return true;
|
||||
}
|
||||
if(label == null)
|
||||
label = id;
|
||||
MarkerIcon ico = MarkerAPIImpl.getMarkerIconImpl(id);
|
||||
|
@ -2181,10 +2188,9 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
return true;
|
||||
}
|
||||
/* Open stream to filename */
|
||||
File iconf = new File(file);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(iconf);
|
||||
fis = new FileInputStream(new File(plugin.getImportFolder(), file));
|
||||
/* Create new icon */
|
||||
MarkerIcon mi = api.createMarkerIcon(id, label, fis);
|
||||
if(mi == null) {
|
||||
|
@ -3198,6 +3204,12 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
private static boolean validateImportFile(String fname) {
|
||||
if ((fname.indexOf('/') >= 0) || (fname.indexOf('\\') >= 0)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/** Process importdesc for given item */
|
||||
private static boolean processImportDesc(DynmapCore plugin, DynmapCommandSender sender, String cmd, String commandLabel, String[] args) {
|
||||
if(args.length > 1) {
|
||||
|
@ -3211,13 +3223,17 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
}
|
||||
String f = parms.get(ARG_FILE);
|
||||
if (f == null) {
|
||||
sender.sendMessage("Error: no '" + ARG_FILE + "' parameter");
|
||||
sender.sendMessage("file:\"filename\" required");
|
||||
return true;
|
||||
}
|
||||
if (!validateImportFile(f)) {
|
||||
sender.sendMessage("Error: '" + ARG_FILE + "' cannot include directory separators - must be just filename in " + plugin.getImportFolder().getAbsolutePath() + " directory");
|
||||
return true;
|
||||
}
|
||||
FileReader fr = null;
|
||||
String val = null;
|
||||
try {
|
||||
fr = new FileReader(f);
|
||||
fr = new FileReader(new File(plugin.getImportFolder(), f));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char[] buf = new char[512];
|
||||
int len;
|
||||
|
@ -3258,13 +3274,17 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
}
|
||||
String f = parms.get(ARG_FILE);
|
||||
if (f == null) {
|
||||
sender.sendMessage("Error: no '" + ARG_FILE + "' parameter");
|
||||
sender.sendMessage("file:\"filename\" required");
|
||||
return true;
|
||||
}
|
||||
if (!validateImportFile(f)) {
|
||||
sender.sendMessage("Error: '" + ARG_FILE + "' cannot include directory separators - must be just filename in " + plugin.getImportFolder().getAbsolutePath() + " directory");
|
||||
return true;
|
||||
}
|
||||
FileReader fr = null;
|
||||
String val = null;
|
||||
try {
|
||||
fr = new FileReader(f);
|
||||
fr = new FileReader(new File(plugin.getImportFolder(), f));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char[] buf = new char[512];
|
||||
int len;
|
||||
|
@ -3328,10 +3348,10 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
mi = MarkerAPIImpl.getMarkerIconImpl(MarkerIcon.DEFAULT);
|
||||
mdata.put("icon", mi.getMarkerIconID());
|
||||
mdata.put("dim", mi.getMarkerIconSize().getSize());
|
||||
mdata.put("label", Client.sanitizeHTML(m.getLabel()));
|
||||
mdata.put("label", m.getLabel());
|
||||
mdata.put("markup", m.isLabelMarkup());
|
||||
if(m.getDescription() != null)
|
||||
mdata.put("desc", Client.sanitizeHTML(m.getDescription()));
|
||||
mdata.put("desc", m.getDescription());
|
||||
if (m.getMinZoom() >= 0) {
|
||||
mdata.put("minzoom", m.getMinZoom());
|
||||
}
|
||||
|
@ -3364,10 +3384,10 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
mdata.put("opacity", m.getLineOpacity());
|
||||
mdata.put("fillopacity", m.getFillOpacity());
|
||||
mdata.put("weight", m.getLineWeight());
|
||||
mdata.put("label", Client.sanitizeHTML(m.getLabel()));
|
||||
mdata.put("label", m.getLabel());
|
||||
mdata.put("markup", m.isLabelMarkup());
|
||||
if(m.getDescription() != null)
|
||||
mdata.put("desc", Client.sanitizeHTML(m.getDescription()));
|
||||
mdata.put("desc", m.getDescription());
|
||||
if (m.getMinZoom() >= 0) {
|
||||
mdata.put("minzoom", m.getMinZoom());
|
||||
}
|
||||
|
@ -3399,10 +3419,10 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
mdata.put("color", String.format("#%06X", m.getLineColor()));
|
||||
mdata.put("opacity", m.getLineOpacity());
|
||||
mdata.put("weight", m.getLineWeight());
|
||||
mdata.put("label", Client.sanitizeHTML(m.getLabel()));
|
||||
mdata.put("label", m.getLabel());
|
||||
mdata.put("markup", m.isLabelMarkup());
|
||||
if(m.getDescription() != null)
|
||||
mdata.put("desc", Client.sanitizeHTML(m.getDescription()));
|
||||
mdata.put("desc", m.getDescription());
|
||||
if (m.getMinZoom() >= 0) {
|
||||
mdata.put("minzoom", m.getMinZoom());
|
||||
}
|
||||
|
@ -3429,10 +3449,10 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
mdata.put("opacity", m.getLineOpacity());
|
||||
mdata.put("fillopacity", m.getFillOpacity());
|
||||
mdata.put("weight", m.getLineWeight());
|
||||
mdata.put("label", Client.sanitizeHTML(m.getLabel()));
|
||||
mdata.put("label", m.getLabel());
|
||||
mdata.put("markup", m.isLabelMarkup());
|
||||
if(m.getDescription() != null)
|
||||
mdata.put("desc", Client.sanitizeHTML(m.getDescription()));
|
||||
mdata.put("desc", m.getDescription());
|
||||
if (m.getMinZoom() >= 0) {
|
||||
mdata.put("minzoom", m.getMinZoom());
|
||||
}
|
||||
|
@ -3458,7 +3478,7 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener<DynmapWorld> {
|
|||
@Override
|
||||
public void triggered(DynmapWorld t) {
|
||||
/* Update markers for now-active world */
|
||||
dirty_worlds.add(t.getName());
|
||||
dirty_worlds.put(t.getName(),"");
|
||||
}
|
||||
|
||||
/* Remove icon */
|
||||
|
|
|
@ -81,7 +81,7 @@ class MarkerIconImpl implements MarkerIcon {
|
|||
return node;
|
||||
}
|
||||
|
||||
boolean loadPersistentData(ConfigurationNode node) {
|
||||
boolean loadPersistentData(ConfigurationNode node, boolean isSafe) {
|
||||
if(is_builtin)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ class MarkerImpl implements Marker {
|
|||
MarkerImpl(String id, MarkerSetImpl set) {
|
||||
markerid = id;
|
||||
markerset = set;
|
||||
label = Client.encodeForHTML(id);
|
||||
label = Client.sanitizeHTML(Client.encodeForHTML(id));
|
||||
markup = false;
|
||||
desc = null;
|
||||
x = z = 0; y = 64; world = normalized_world = "world";
|
||||
|
@ -75,15 +75,17 @@ class MarkerImpl implements Marker {
|
|||
* Load marker from configuration node
|
||||
* @param node - configuration node
|
||||
*/
|
||||
boolean loadPersistentData(ConfigurationNode node) {
|
||||
boolean loadPersistentData(ConfigurationNode node, boolean isSafe) {
|
||||
markup = node.getBoolean("markup", false);
|
||||
label = MarkerAPIImpl.escapeForHTMLIfNeeded(node.getString("label", markerid), markup);
|
||||
if (!isSafe) label = Client.sanitizeHTML(label);
|
||||
x = node.getDouble("x", 0);
|
||||
y = node.getDouble("y", 64);
|
||||
z = node.getDouble("z", 0);
|
||||
world = node.getString("world", "world");
|
||||
normalized_world = DynmapWorld.normalizeWorldName(world);
|
||||
desc = node.getString("desc", null);
|
||||
if (!isSafe) desc = Client.sanitizeHTML(desc);
|
||||
minzoom = node.getInteger("minzoom", -1);
|
||||
maxzoom = node.getInteger("maxzoom", -1);
|
||||
icon = MarkerAPIImpl.getMarkerIconImpl(node.getString("icon", MarkerIcon.DEFAULT));
|
||||
|
@ -168,7 +170,7 @@ class MarkerImpl implements Marker {
|
|||
@Override
|
||||
public void setLabel(String lbl, boolean markup) {
|
||||
if(markerset == null) return;
|
||||
label = markup ? lbl : Client.encodeForHTML(lbl);
|
||||
label = Client.sanitizeHTML(markup ? lbl : Client.encodeForHTML(lbl));
|
||||
this.markup = markup;
|
||||
MarkerAPIImpl.markerUpdated(this, MarkerUpdate.UPDATED);
|
||||
if(ispersistent)
|
||||
|
@ -239,6 +241,7 @@ class MarkerImpl implements Marker {
|
|||
@Override
|
||||
public void setDescription(String desc) {
|
||||
if(markerset == null) return;
|
||||
desc = Client.sanitizeHTML(desc);
|
||||
if((this.desc == null) || (this.desc.equals(desc) == false)) {
|
||||
this.desc = desc;
|
||||
MarkerAPIImpl.markerUpdated(this, MarkerUpdate.UPDATED);
|
||||
|
|
|
@ -449,14 +449,14 @@ class MarkerSetImpl implements MarkerSet {
|
|||
* Load marker from configuration node
|
||||
* @param node - configuration node
|
||||
*/
|
||||
boolean loadPersistentData(ConfigurationNode node) {
|
||||
boolean loadPersistentData(ConfigurationNode node, boolean isSafe) {
|
||||
label = node.getString("label", setid); /* Get label */
|
||||
ConfigurationNode markernode = node.getNode("markers");
|
||||
if (markernode != null) {
|
||||
for(String id : markernode.keySet()) {
|
||||
MarkerImpl marker = new MarkerImpl(id, this); /* Make and load marker */
|
||||
ConfigurationNode cfg = markernode.getNode(id);
|
||||
if ((cfg != null) && marker.loadPersistentData(cfg)) {
|
||||
if ((cfg != null) && marker.loadPersistentData(cfg, isSafe)) {
|
||||
markers.put(id, marker);
|
||||
}
|
||||
else {
|
||||
|
@ -470,7 +470,7 @@ class MarkerSetImpl implements MarkerSet {
|
|||
for(String id : areamarkernode.keySet()) {
|
||||
AreaMarkerImpl marker = new AreaMarkerImpl(id, this); /* Make and load marker */
|
||||
ConfigurationNode cfg = areamarkernode.getNode(id);
|
||||
if ((cfg != null) && marker.loadPersistentData(cfg)) {
|
||||
if ((cfg != null) && marker.loadPersistentData(cfg, isSafe)) {
|
||||
areamarkers.put(id, marker);
|
||||
if(marker.getBoostFlag()) {
|
||||
if(boostingareamarkers == null) {
|
||||
|
@ -496,7 +496,7 @@ class MarkerSetImpl implements MarkerSet {
|
|||
for(String id : linemarkernode.keySet()) {
|
||||
PolyLineMarkerImpl marker = new PolyLineMarkerImpl(id, this); /* Make and load marker */
|
||||
ConfigurationNode cfg = linemarkernode.getNode(id);
|
||||
if ((cfg != null) && marker.loadPersistentData(cfg)) {
|
||||
if ((cfg != null) && marker.loadPersistentData(cfg, isSafe)) {
|
||||
linemarkers.put(id, marker);
|
||||
}
|
||||
else {
|
||||
|
@ -510,7 +510,7 @@ class MarkerSetImpl implements MarkerSet {
|
|||
for(String id : circlemarkernode.keySet()) {
|
||||
CircleMarkerImpl marker = new CircleMarkerImpl(id, this); /* Make and load marker */
|
||||
ConfigurationNode cfg = circlemarkernode.getNode(id);
|
||||
if ((cfg != null) && marker.loadPersistentData(cfg)) {
|
||||
if ((cfg != null) && marker.loadPersistentData(cfg, isSafe)) {
|
||||
circlemarkers.put(id, marker);
|
||||
if(marker.getBoostFlag()) {
|
||||
if(boostingcirclemarkers == null) {
|
||||
|
|
|
@ -71,7 +71,7 @@ class PlayerSetImpl implements PlayerSet {
|
|||
* Load marker from configuration node
|
||||
* @param node - configuration node
|
||||
*/
|
||||
boolean loadPersistentData(ConfigurationNode node) {
|
||||
boolean loadPersistentData(ConfigurationNode node, boolean isSafe) {
|
||||
List<String> plist = node.getList("players");
|
||||
if(plist != null) {
|
||||
players.clear();
|
||||
|
|
|
@ -53,6 +53,7 @@ class PolyLineMarkerImpl implements PolyLineMarker {
|
|||
label = markup ? lbl : Client.encodeForHTML(lbl);
|
||||
else
|
||||
label = markup ? id : Client.encodeForHTML(id);
|
||||
label = Client.sanitizeHTML(label);
|
||||
this.markup = markup;
|
||||
this.corners = new ArrayList<Coord>();
|
||||
for(int i = 0; i < x.length; i++) {
|
||||
|
@ -74,7 +75,7 @@ class PolyLineMarkerImpl implements PolyLineMarker {
|
|||
PolyLineMarkerImpl(String id, MarkerSetImpl set) {
|
||||
markerid = id;
|
||||
markerset = set;
|
||||
label = Client.encodeForHTML(id);
|
||||
label = Client.sanitizeHTML(Client.encodeForHTML(id));
|
||||
markup = false;
|
||||
desc = null;
|
||||
corners = new ArrayList<Coord>();
|
||||
|
@ -86,9 +87,10 @@ class PolyLineMarkerImpl implements PolyLineMarker {
|
|||
* Load marker from configuration node
|
||||
* @param node - configuration node
|
||||
*/
|
||||
boolean loadPersistentData(ConfigurationNode node) {
|
||||
boolean loadPersistentData(ConfigurationNode node, boolean isSafe) {
|
||||
markup = node.getBoolean("markup", false);
|
||||
label = MarkerAPIImpl.escapeForHTMLIfNeeded(node.getString("label", markerid), markup);
|
||||
if (!isSafe) label = Client.sanitizeHTML(label);
|
||||
List<Double> xx = node.getList("x");
|
||||
List<Double> yy = node.getList("y");
|
||||
List<Double> zz = node.getList("z");
|
||||
|
@ -101,6 +103,7 @@ class PolyLineMarkerImpl implements PolyLineMarker {
|
|||
world = node.getString("world", "world");
|
||||
normalized_world = DynmapWorld.normalizeWorldName(world);
|
||||
desc = node.getString("desc", null);
|
||||
if (!isSafe) desc = Client.sanitizeHTML(desc);
|
||||
lineweight = node.getInteger("strokeWeight", -1);
|
||||
if(lineweight == -1) { /* Handle typo-saved value */
|
||||
lineweight = node.getInteger("stokeWeight", 3);
|
||||
|
@ -164,7 +167,7 @@ class PolyLineMarkerImpl implements PolyLineMarker {
|
|||
@Override
|
||||
public void setLabel(String lbl, boolean markup) {
|
||||
if(markerset == null) return;
|
||||
label = markup ? lbl : Client.encodeForHTML(lbl);
|
||||
label = markup ? Client.sanitizeHTML(lbl) : Client.encodeForHTML(lbl);
|
||||
this.markup = markup;
|
||||
MarkerAPIImpl.polyLineMarkerUpdated(this, MarkerUpdate.UPDATED);
|
||||
if(ispersistent)
|
||||
|
@ -223,6 +226,7 @@ class PolyLineMarkerImpl implements PolyLineMarker {
|
|||
@Override
|
||||
public void setDescription(String desc) {
|
||||
if(markerset == null) return;
|
||||
desc = Client.sanitizeHTML(desc);
|
||||
if((this.desc == null) || (this.desc.equals(desc) == false)) {
|
||||
this.desc = desc;
|
||||
MarkerAPIImpl.polyLineMarkerUpdated(this, MarkerUpdate.UPDATED);
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
package org.dynmap.modsupport.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.dynmap.modsupport.BlockModel;
|
||||
|
||||
public abstract class BlockModelImpl implements BlockModel {
|
||||
private int[] ids = new int[0];
|
||||
private String[] names = new String[0];
|
||||
private int metaMask = -1;
|
||||
private BitSet meta = null;
|
||||
private List<Map<String, String>> blockstates = null;
|
||||
protected final ModModelDefinitionImpl mdf;
|
||||
|
||||
@Deprecated
|
||||
public BlockModelImpl(int blkid, ModModelDefinitionImpl mdf) {
|
||||
addBlockID(blkid);
|
||||
this.mdf = mdf;
|
||||
|
@ -24,6 +32,7 @@ public abstract class BlockModelImpl implements BlockModel {
|
|||
* @param blockID - block ID
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addBlockID(int blockID) {
|
||||
if (blockID > 0) {
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
|
@ -56,6 +65,7 @@ public abstract class BlockModelImpl implements BlockModel {
|
|||
* @return configured IDs
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int[] getBlockIDs() {
|
||||
return ids;
|
||||
}
|
||||
|
@ -74,16 +84,12 @@ public abstract class BlockModelImpl implements BlockModel {
|
|||
* @param data - value to match (-1 = all, 0-15 is meta value to match)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setMetaValue(int data) {
|
||||
if (data < 0) { // Setting to all
|
||||
metaMask = METAMASK_ALL;
|
||||
}
|
||||
else if (data < 16) {
|
||||
if (metaMask == METAMASK_ALL) {
|
||||
metaMask = 0;
|
||||
}
|
||||
metaMask |= (1 << data);
|
||||
}
|
||||
if (meta == null) {
|
||||
meta = new BitSet();
|
||||
}
|
||||
meta.set(data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,12 +97,35 @@ public abstract class BlockModelImpl implements BlockModel {
|
|||
* @return matching metadata mask: bit N is set if given metadata value matches
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getMetaValueMask() {
|
||||
return metaMask;
|
||||
if (meta == null) { return METAMASK_ALL; }
|
||||
return (int) meta.toLongArray()[0]; // Only works for 32 flags
|
||||
}
|
||||
|
||||
/**
|
||||
* Set matching block state mapping
|
||||
* Any key-value pairs included must match, while any not included are assumed to match unconditionall
|
||||
* @param statemap - map of attribute value pairs
|
||||
*/
|
||||
public void setBlockStateMapping(Map<String, String> statemap) {
|
||||
if (blockstates == null) {
|
||||
blockstates = new ArrayList<Map<String, String>>();
|
||||
}
|
||||
Map<String, String> nmap = new HashMap<String, String>();
|
||||
nmap.putAll(statemap);
|
||||
blockstates.add(nmap);
|
||||
}
|
||||
/**
|
||||
* Get all state mappings accumulated for the block model
|
||||
*/
|
||||
public List<Map<String, String>> getBlockStateMappings() {
|
||||
return blockstates;
|
||||
}
|
||||
|
||||
public abstract String getLine();
|
||||
|
||||
// This is now getting state mappings too
|
||||
protected String getIDsAndMeta() {
|
||||
if ((ids.length == 0) && (names.length == 0)) {
|
||||
return null;
|
||||
|
@ -118,18 +147,34 @@ public abstract class BlockModelImpl implements BlockModel {
|
|||
}
|
||||
s += "id=%" + names[i];
|
||||
}
|
||||
// Add meta
|
||||
if (this.metaMask == METAMASK_ALL) {
|
||||
s += ",data=*";
|
||||
// If we have state data, favor this
|
||||
if (this.blockstates != null) {
|
||||
for (Map<String, String> rec : this.blockstates) {
|
||||
// If no state, skip
|
||||
if (rec.size() == 0) { continue; }
|
||||
s += ",state=";
|
||||
boolean first = true;
|
||||
for (Entry<String, String> r : rec.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
s += '/';
|
||||
}
|
||||
s += r.getKey() + ":" + r.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((metaMask & (1 << i)) != 0) {
|
||||
s += ",data=" + i;
|
||||
}
|
||||
}
|
||||
// If we have meta data, add this next
|
||||
if (this.meta != null) {
|
||||
for (int i = meta.nextSetBit(0); i != -1; i = meta.nextSetBit(i + 1)) {
|
||||
s += ",data=" + i;
|
||||
}
|
||||
}
|
||||
// If neither, just state=*
|
||||
if ((this.meta == null) && (this.blockstates == null)) {
|
||||
s += ",state=*";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,11 @@ package org.dynmap.modsupport.impl;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.dynmap.hdmap.TexturePack;
|
||||
import org.dynmap.modsupport.BlockSide;
|
||||
|
@ -13,7 +18,8 @@ import org.dynmap.modsupport.TransparencyMode;
|
|||
public class BlockTextureRecordImpl implements BlockTextureRecord {
|
||||
private int[] ids = new int[0];
|
||||
private String[] names = new String[0];
|
||||
private int metaMask = -1;
|
||||
private BitSet meta = null;
|
||||
private List<Map<String, String>> blockstates = null;
|
||||
private TransparencyMode transmode = TransparencyMode.OPAQUE;
|
||||
|
||||
private static class TexturePatch {
|
||||
|
@ -96,6 +102,7 @@ public class BlockTextureRecordImpl implements BlockTextureRecord {
|
|||
TexturePack.COLORMOD_FOLIAGEMULTTONED // FOLIAGEMULTTONED
|
||||
};
|
||||
|
||||
@Deprecated
|
||||
public BlockTextureRecordImpl(int blkid) {
|
||||
addBlockID(blkid);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
@ -115,6 +122,7 @@ public class BlockTextureRecordImpl implements BlockTextureRecord {
|
|||
* @param blockID - block ID
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addBlockID(int blockID) {
|
||||
if (blockID > 0) {
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
|
@ -147,6 +155,7 @@ public class BlockTextureRecordImpl implements BlockTextureRecord {
|
|||
* @return configured IDs
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int[] getBlockIDs() {
|
||||
return ids;
|
||||
}
|
||||
|
@ -165,16 +174,12 @@ public class BlockTextureRecordImpl implements BlockTextureRecord {
|
|||
* @param data - value to match (-1 = all, 0-15 is meta value to match)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setMetaValue(int data) {
|
||||
if (data < 0) { // Setting to all
|
||||
metaMask = METAMASK_ALL;
|
||||
}
|
||||
else if (data < 16) {
|
||||
if (metaMask == METAMASK_ALL) {
|
||||
metaMask = 0;
|
||||
}
|
||||
metaMask |= (1 << data);
|
||||
}
|
||||
if (meta == null) {
|
||||
meta = new BitSet();
|
||||
}
|
||||
meta.set(data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,10 +187,32 @@ public class BlockTextureRecordImpl implements BlockTextureRecord {
|
|||
* @return matching metadata mask: bit N is set if given metadata value matches
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getMetaValueMask() {
|
||||
return metaMask;
|
||||
if (meta == null) { return METAMASK_ALL; }
|
||||
return (int) meta.toLongArray()[0]; // Only works for 32 flags
|
||||
}
|
||||
|
||||
/**
|
||||
* Set matching block state mapping
|
||||
* Any key-value pairs included must match, while any not included are assumed to match unconditionall
|
||||
* @param statemap - map of attribute value pairs
|
||||
*/
|
||||
public void setBlockStateMapping(Map<String, String> statemap) {
|
||||
if (blockstates == null) {
|
||||
blockstates = new ArrayList<Map<String, String>>();
|
||||
}
|
||||
Map<String, String> nmap = new HashMap<String, String>();
|
||||
nmap.putAll(statemap);
|
||||
blockstates.add(nmap);
|
||||
}
|
||||
/**
|
||||
* Get all state mappings accumulated for the block model
|
||||
*/
|
||||
public List<Map<String, String>> getBlockStateMappings() {
|
||||
return blockstates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set transparency mode for block
|
||||
* @param mode - transparency mode
|
||||
|
@ -503,16 +530,32 @@ public class BlockTextureRecordImpl implements BlockTextureRecord {
|
|||
s += "id=%" + names[i];
|
||||
idcnt++;
|
||||
}
|
||||
// Add meta
|
||||
if (this.metaMask == METAMASK_ALL) {
|
||||
s += ",data=*";
|
||||
// If we have state data, favor this
|
||||
if (this.blockstates != null) {
|
||||
for (Map<String, String> rec : this.blockstates) {
|
||||
if (rec.size() == 0) { continue; } // Skip if none
|
||||
s += ",state=";
|
||||
boolean first = true;
|
||||
for (Entry<String, String> r : rec.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
s += '/';
|
||||
}
|
||||
s += r.getKey() + ":" + r.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((metaMask & (1 << i)) != 0) {
|
||||
s += ",data=" + i;
|
||||
}
|
||||
}
|
||||
// If we have meta data, add this next
|
||||
if (this.meta != null) {
|
||||
for (int i = meta.nextSetBit(0); i != -1; i = meta.nextSetBit(i + 1)) {
|
||||
s += ",data=" + i;
|
||||
}
|
||||
}
|
||||
// If neither, just state=*
|
||||
if ((this.meta == null) && (this.blockstates == null)) {
|
||||
s += ",state=*";
|
||||
}
|
||||
for (int i = 0; i < txtPatches.size(); i++) {
|
||||
TexturePatch tp = txtPatches.get(i);
|
||||
|
|
|
@ -12,6 +12,7 @@ public class BoxBlockModelImpl extends BlockModelImpl implements BoxBlockModel {
|
|||
private double zmin = 0.0;
|
||||
private double zmax = 1.0;
|
||||
|
||||
@Deprecated
|
||||
public BoxBlockModelImpl(int blkid, ModModelDefinitionImpl mdf) {
|
||||
super(blkid, mdf);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
package org.dynmap.modsupport.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.dynmap.DynmapCore;
|
||||
import org.dynmap.modsupport.CopyBlockTextureRecord;
|
||||
import org.dynmap.modsupport.TransparencyMode;
|
||||
|
||||
public class CopyBlockTextureRecordImpl implements CopyBlockTextureRecord {
|
||||
private int[] ids = new int[0];
|
||||
private String[] names = new String[0];
|
||||
private int metaMask = -1;
|
||||
private BitSet meta = null;
|
||||
private List<Map<String, String>> blockstates = null;
|
||||
private final int srcid;
|
||||
private final String srcname;
|
||||
private final int srcmeta;
|
||||
private final Map<String, String> srcstatemap;
|
||||
private TransparencyMode mode = null;
|
||||
|
||||
private int isNumber(String v) {
|
||||
|
@ -28,6 +35,7 @@ public class CopyBlockTextureRecordImpl implements CopyBlockTextureRecord {
|
|||
this.srcid = srcid;
|
||||
this.srcname = null;
|
||||
this.srcmeta = srcmeta;
|
||||
this.srcstatemap = null;
|
||||
}
|
||||
|
||||
public CopyBlockTextureRecordImpl(String blkname, String srcname, int srcmeta) {
|
||||
|
@ -42,6 +50,23 @@ public class CopyBlockTextureRecordImpl implements CopyBlockTextureRecord {
|
|||
this.srcid = id;
|
||||
}
|
||||
this.srcmeta = srcmeta;
|
||||
this.srcstatemap = null;
|
||||
}
|
||||
|
||||
public CopyBlockTextureRecordImpl(String blkname, String srcname, Map<String, String> srcstatemap) {
|
||||
addBlockName(blkname);
|
||||
int id = isNumber(srcname);
|
||||
if (id < 0) {
|
||||
this.srcname = srcname;
|
||||
this.srcid = 0;
|
||||
}
|
||||
else {
|
||||
this.srcname = null;
|
||||
this.srcid = id;
|
||||
}
|
||||
this.srcmeta = -1;
|
||||
this.srcstatemap = new HashMap<String, String>();
|
||||
this.srcstatemap.putAll(srcstatemap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,16 +124,12 @@ public class CopyBlockTextureRecordImpl implements CopyBlockTextureRecord {
|
|||
* @param data - value to match (-1 = all, 0-15 is meta value to match)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setMetaValue(int data) {
|
||||
if (data < 0) { // Setting to all
|
||||
metaMask = METAMASK_ALL;
|
||||
}
|
||||
else if (data < 16) {
|
||||
if (metaMask == METAMASK_ALL) {
|
||||
metaMask = 0;
|
||||
}
|
||||
metaMask |= (1 << data);
|
||||
}
|
||||
if (meta == null) {
|
||||
meta = new BitSet();
|
||||
}
|
||||
meta.set(data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,8 +137,32 @@ public class CopyBlockTextureRecordImpl implements CopyBlockTextureRecord {
|
|||
* @return matching metadata mask: bit N is set if given metadata value matches
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getMetaValueMask() {
|
||||
return metaMask;
|
||||
if (meta == null) { return METAMASK_ALL; }
|
||||
return (int) meta.toLongArray()[0]; // Only works for 32 flags
|
||||
}
|
||||
|
||||
/**
|
||||
* Set matching block state mapping
|
||||
* Any key-value pairs included must match, while any not included are assumed to match unconditionall
|
||||
* @param statemap - map of attribute value pairs
|
||||
*/
|
||||
@Override
|
||||
public void setBlockStateMapping(Map<String, String> statemap) {
|
||||
if (blockstates == null) {
|
||||
blockstates = new ArrayList<Map<String, String>>();
|
||||
}
|
||||
Map<String, String> nmap = new HashMap<String, String>();
|
||||
nmap.putAll(statemap);
|
||||
blockstates.add(nmap);
|
||||
}
|
||||
/**
|
||||
* Get all state mappings accumulated for the block model
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, String>> getBlockStateMappings() {
|
||||
return blockstates;
|
||||
}
|
||||
|
||||
public String getLine() {
|
||||
|
@ -143,23 +188,57 @@ public class CopyBlockTextureRecordImpl implements CopyBlockTextureRecord {
|
|||
s += "id=%" + names[i];
|
||||
idcnt++;
|
||||
}
|
||||
// Add meta
|
||||
if (this.metaMask == METAMASK_ALL) {
|
||||
s += ",data=*";
|
||||
// If we have state data, favor this
|
||||
if (this.blockstates != null) {
|
||||
for (Map<String, String> rec : this.blockstates) {
|
||||
if (rec.size() == 0) { continue; } // Skip if none
|
||||
s += ",state=";
|
||||
boolean first = true;
|
||||
for (Entry<String, String> r : rec.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
s += '/';
|
||||
}
|
||||
s += r.getKey() + ":" + r.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((metaMask & (1 << i)) != 0) {
|
||||
s += ",data=" + i;
|
||||
}
|
||||
}
|
||||
// If we have meta data, add this next
|
||||
if (this.meta != null) {
|
||||
for (int i = meta.nextSetBit(0); i != -1; i = meta.nextSetBit(i + 1)) {
|
||||
s += ",data=" + i;
|
||||
}
|
||||
}
|
||||
// If neither, just state=*
|
||||
if ((this.meta == null) && (this.blockstates == null)) {
|
||||
s += ",state=*";
|
||||
}
|
||||
if (srcname != null) {
|
||||
s += ",srcid=%" + srcname + ",srcmeta=" + srcmeta;
|
||||
s += ",srcid=%" + srcname;
|
||||
}
|
||||
else {
|
||||
s += ",srcid=" + srcid + ",srcmeta=" + srcmeta;
|
||||
s += ",srcid=" + srcid;
|
||||
}
|
||||
// If source state, use it
|
||||
if (this.srcstatemap != null) {
|
||||
s += ",srcstate=";
|
||||
boolean first = true;
|
||||
for (Entry<String, String> r : this.srcstatemap.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
s += '/';
|
||||
}
|
||||
s += r.getKey() + ":" + r.getValue();
|
||||
}
|
||||
}
|
||||
else {
|
||||
s += ",srcmeta=" + srcmeta;
|
||||
}
|
||||
|
||||
switch (this.mode) {
|
||||
case TRANSPARENT:
|
||||
s += ",transparency=TRANSPARENT";
|
||||
|
@ -174,15 +253,25 @@ public class CopyBlockTextureRecordImpl implements CopyBlockTextureRecord {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getSourceBlockID() {
|
||||
return srcid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getSourceMeta() {
|
||||
return srcmeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sourc state mappings accumulated for the block model
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> getSourceBlockStateMapping() {
|
||||
return srcstatemap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransparencyMode(TransparencyMode mode) {
|
||||
this.mode = mode;
|
||||
|
@ -192,4 +281,8 @@ public class CopyBlockTextureRecordImpl implements CopyBlockTextureRecord {
|
|||
public TransparencyMode getTransparencyMode() {
|
||||
return mode;
|
||||
}
|
||||
@Override
|
||||
public String getSourceBlockName() {
|
||||
return srcname;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ public class CuboidBlockModelImpl extends BlockModelImpl implements CuboidBlockM
|
|||
private ArrayList<Cuboid> cuboids = new ArrayList<Cuboid>();
|
||||
private ArrayList<Crossed> crosseds = new ArrayList<Crossed>();
|
||||
|
||||
@Deprecated
|
||||
public CuboidBlockModelImpl(int blkid, ModModelDefinitionImpl mdf) {
|
||||
super(blkid, mdf);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.dynmap.modsupport.DoorBlockModel;
|
|||
|
||||
public class DoorBlockModelImpl extends BlockModelImpl implements DoorBlockModel {
|
||||
|
||||
@Deprecated
|
||||
public DoorBlockModelImpl(int blkid, ModModelDefinitionImpl mdf) {
|
||||
super(blkid, mdf);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package org.dynmap.modsupport.impl;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
|
@ -26,6 +28,7 @@ import org.dynmap.renderer.RenderPatchFactory.SideVisible;
|
|||
import org.dynmap.utils.PatchDefinition;
|
||||
import org.dynmap.utils.PatchDefinitionFactory;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ModModelDefinitionImpl implements ModModelDefinition {
|
||||
private final ModTextureDefinitionImpl txtDef;
|
||||
private boolean published = false;
|
||||
|
@ -61,12 +64,14 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public VolumetricBlockModel addVolumetricModel(int blockid, int scale) {
|
||||
VolumetricBlockModelImpl mod = new VolumetricBlockModelImpl(blockid, this, scale);
|
||||
blkModel.add(mod);
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
@Deprecated
|
||||
public VolumetricBlockModel addVolumetricModel(String blockname, int scale) {
|
||||
VolumetricBlockModelImpl mod = new VolumetricBlockModelImpl(blockname, this, scale);
|
||||
blkModel.add(mod);
|
||||
|
@ -74,6 +79,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public StairBlockModel addStairModel(int blockid) {
|
||||
StairBlockModelImpl mod = new StairBlockModelImpl(blockid, this);
|
||||
blkModel.add(mod);
|
||||
|
@ -87,6 +93,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public WallFenceBlockModel addWallFenceModel(int blockid, FenceType type) {
|
||||
WallFenceBlockModelImpl mod = new WallFenceBlockModelImpl(blockid, this, type);
|
||||
blkModel.add(mod);
|
||||
|
@ -100,6 +107,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public CuboidBlockModel addCuboidModel(int blockid) {
|
||||
CuboidBlockModelImpl mod = new CuboidBlockModelImpl(blockid, this);
|
||||
blkModel.add(mod);
|
||||
|
@ -114,6 +122,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PaneBlockModel addPaneModel(int blockid) {
|
||||
PaneBlockModelImpl mod = new PaneBlockModelImpl(blockid, this);
|
||||
blkModel.add(mod);
|
||||
|
@ -127,6 +136,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PlantBlockModel addPlantModel(int blockid) {
|
||||
PlantBlockModelImpl mod = new PlantBlockModelImpl(blockid, this);
|
||||
blkModel.add(mod);
|
||||
|
@ -140,6 +150,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public BoxBlockModel addBoxModel(int blockid) {
|
||||
BoxBlockModelImpl mod = new BoxBlockModelImpl(blockid, this);
|
||||
blkModel.add(mod);
|
||||
|
@ -153,6 +164,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public DoorBlockModel addDoorModel(int blockid) {
|
||||
DoorBlockModelImpl mod = new DoorBlockModelImpl(blockid, this);
|
||||
blkModel.add(mod);
|
||||
|
@ -166,6 +178,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PatchBlockModel addPatchModel(int blockid) {
|
||||
PatchBlockModelImpl mod = new PatchBlockModelImpl(blockid, this);
|
||||
blkModel.add(mod);
|
||||
|
@ -179,6 +192,7 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PatchBlockModel addRotatedPatchModel(int blockid,
|
||||
PatchBlockModel model, int xrot, int yrot, int zrot) {
|
||||
PatchBlockModelImpl mod = new PatchBlockModelImpl(blockid, this, model, xrot, yrot, zrot);
|
||||
|
@ -199,12 +213,6 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
blkModel.add(mod);
|
||||
return mod;
|
||||
}
|
||||
@Override
|
||||
public ModelBlockModel addRotatedModelBlockModel(String blockname, ModelBlockModel model, int xrot, int yrot, int zrot) {
|
||||
ModelBlockModelImpl mod = new ModelBlockModelImpl(blockname, this, model, xrot, yrot, zrot);
|
||||
blkModel.add(mod);
|
||||
return mod;
|
||||
}
|
||||
|
||||
public String getPatchID(double x0, double y0, double z0, double xu,
|
||||
double yu, double zu, double xv, double yv, double zv, double umin,
|
||||
|
@ -223,8 +231,8 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
return id;
|
||||
}
|
||||
|
||||
public String getModelFacePatchID(double[] from, double[] to, BlockSide face, double[] uv, ModelBlockModel.SideRotation rot, int textureid) {
|
||||
PatchDefinition pd = pdf.getModelFace(from, to, face, uv, rot, textureid);
|
||||
public String getModelFacePatchID(double[] from, double[] to, BlockSide face, double[] uv, ModelBlockModel.SideRotation rot, boolean shade, int textureid) {
|
||||
PatchDefinition pd = pdf.getModelFace(from, to, face, uv, rot, shade, textureid);
|
||||
if (pd == null)
|
||||
return null; // Invalid patch
|
||||
for (int i = 0; i < blkPatch.size(); i++) {
|
||||
|
@ -268,9 +276,9 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
return;
|
||||
}
|
||||
File f = new File(destdir, this.txtDef.getModID() + "-models.txt");
|
||||
FileWriter fw = null;
|
||||
Writer fw = null;
|
||||
try {
|
||||
fw = new FileWriter(f);
|
||||
fw = new BufferedWriter(new FileWriter(f));
|
||||
// Write modname line
|
||||
String s = "modname:" + this.txtDef.getModID();
|
||||
fw.write(s + "\n\n");
|
||||
|
@ -287,6 +295,15 @@ public class ModModelDefinitionImpl implements ModModelDefinition {
|
|||
case TOP:
|
||||
line += ",visibility=top";
|
||||
break;
|
||||
case TOPFLIP:
|
||||
line += ",visibility=topflip";
|
||||
break;
|
||||
case TOPFLIPV:
|
||||
line += ",visibility=topflipv";
|
||||
break;
|
||||
case TOPFLIPHV:
|
||||
line += ",visibility=topfliphv";
|
||||
break;
|
||||
case FLIP:
|
||||
line += ",visibility=flip";
|
||||
break;
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package org.dynmap.modsupport.impl;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dynmap.modsupport.BigChestTextureFile;
|
||||
import org.dynmap.modsupport.BiomeTextureFile;
|
||||
|
@ -227,6 +230,7 @@ public class ModTextureDefinitionImpl implements ModTextureDefinition {
|
|||
* @return block texture record: use methods to set texture use on faces/patches
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public BlockTextureRecord addBlockTextureRecord(int blockID) {
|
||||
BlockTextureRecordImpl btr = new BlockTextureRecordImpl(blockID);
|
||||
blkTextureRec.add(btr);
|
||||
|
@ -245,6 +249,7 @@ public class ModTextureDefinitionImpl implements ModTextureDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public CopyBlockTextureRecord addCopyBlockTextureRecord(int blockID,
|
||||
int srcBlockID, int srcMeta) {
|
||||
CopyBlockTextureRecordImpl btr = new CopyBlockTextureRecordImpl(blockID, srcBlockID, srcMeta);
|
||||
|
@ -252,6 +257,7 @@ public class ModTextureDefinitionImpl implements ModTextureDefinition {
|
|||
return btr;
|
||||
}
|
||||
@Override
|
||||
@Deprecated
|
||||
public CopyBlockTextureRecord addCopyBlockTextureRecord(String blockname,
|
||||
String srcBlockName, int srcMeta) {
|
||||
CopyBlockTextureRecordImpl btr = new CopyBlockTextureRecordImpl(blockname, srcBlockName, srcMeta);
|
||||
|
@ -259,15 +265,24 @@ public class ModTextureDefinitionImpl implements ModTextureDefinition {
|
|||
return btr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CopyBlockTextureRecord addCopyBlockTextureRecord(String blockname,
|
||||
String srcBlockName, Map<String, String> srcStateMap) {
|
||||
CopyBlockTextureRecordImpl btr = new CopyBlockTextureRecordImpl(blockname, srcBlockName, srcStateMap);
|
||||
blkCopyTextureRec.add(btr);
|
||||
return btr;
|
||||
}
|
||||
|
||||
|
||||
public boolean isPublished() {
|
||||
return published;
|
||||
}
|
||||
|
||||
public void writeToFile(File destdir) throws IOException {
|
||||
File f = new File(destdir, this.modid + "-texture.txt");
|
||||
FileWriter fw = null;
|
||||
Writer fw = null;
|
||||
try {
|
||||
fw = new FileWriter(f);
|
||||
fw = new BufferedWriter(new FileWriter(f));
|
||||
// Write modname line
|
||||
String s = "modname:" + this.modid;
|
||||
fw.write(s + "\n\n");
|
||||
|
|
|
@ -3,10 +3,10 @@ package org.dynmap.modsupport.impl;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.dynmap.modsupport.BlockSide;
|
||||
import org.dynmap.modsupport.ModelBlockModel;
|
||||
import org.dynmap.modsupport.ModelBlockModel.SideRotation;
|
||||
|
||||
public class ModelBlockModelImpl extends BlockModelImpl implements ModelBlockModel {
|
||||
|
||||
|
@ -20,8 +20,11 @@ public class ModelBlockModelImpl extends BlockModelImpl implements ModelBlockMod
|
|||
private double[] from = { 0, 0, 0 };
|
||||
private double[] to = { 16, 16, 16 };
|
||||
private double xrot = 0, yrot = 0, zrot = 0;
|
||||
private boolean shade;
|
||||
private double[] rotorigin;
|
||||
private int modrotx = 0, modroty = 0, modrotz = 0;
|
||||
@Override
|
||||
public void addBlockSide(BlockSide side, double[] uv, SideRotation rot, int textureid) {
|
||||
public void addBlockSide(BlockSide side, double[] uv, SideRotation rot, int textureid, int tintidx) {
|
||||
ModelSide ms = new ModelSide();
|
||||
ms.textureid = textureid;
|
||||
if (uv != null) {
|
||||
|
@ -38,23 +41,17 @@ public class ModelBlockModelImpl extends BlockModelImpl implements ModelBlockMod
|
|||
if (side == BlockSide.FACE_5 || side == BlockSide.X_PLUS) side = BlockSide.EAST;
|
||||
|
||||
sides.put(side, ms);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void addBlockSide(BlockSide side, double[] uv, SideRotation rot, int textureid) {
|
||||
addBlockSide(side, uv, rot, textureid, -1);
|
||||
}
|
||||
}
|
||||
private ArrayList<ModelBlockImpl> boxes = new ArrayList<ModelBlockImpl>();
|
||||
private String rotsourceblockname;
|
||||
private int rotsourcemetaindex;
|
||||
private int xrot, yrot, zrot;
|
||||
|
||||
public ModelBlockModelImpl(String blkname, ModModelDefinitionImpl mdf) {
|
||||
super(blkname, mdf);
|
||||
}
|
||||
|
||||
public ModelBlockModelImpl(String blkname, ModModelDefinitionImpl mdf, ModelBlockModel mod, int xrot, int yrot, int zrot) {
|
||||
super(blkname, mdf);
|
||||
this.rotsourceblockname = mod.getBlockNames()[0];
|
||||
this.rotsourcemetaindex = Integer.numberOfTrailingZeros(mod.getMetaValueMask());
|
||||
this.xrot = xrot; this.yrot = yrot; this.zrot = zrot;
|
||||
}
|
||||
|
||||
private static HashMap<BlockSide, String> fromBlockSide = new HashMap<BlockSide, String>();
|
||||
static {
|
||||
|
@ -62,62 +59,59 @@ public class ModelBlockModelImpl extends BlockModelImpl implements ModelBlockMod
|
|||
fromBlockSide.put(BlockSide.BOTTOM, "d");
|
||||
fromBlockSide.put(BlockSide.NORTH, "n");
|
||||
fromBlockSide.put(BlockSide.SOUTH, "s");
|
||||
fromBlockSide.put(BlockSide.WEST, "e");
|
||||
fromBlockSide.put(BlockSide.EAST, "w");
|
||||
fromBlockSide.put(BlockSide.WEST, "w");
|
||||
fromBlockSide.put(BlockSide.EAST, "e");
|
||||
};
|
||||
|
||||
@Override
|
||||
public String getLine() {
|
||||
String ids = this.getIDsAndMeta();
|
||||
if (ids == null) return null;
|
||||
String line = String.format("patchblock:%s", ids);
|
||||
// If rotating another model
|
||||
if (rotsourceblockname != null) {
|
||||
line += "\npatchrotate:id=" + rotsourceblockname + ",data=" + rotsourcemetaindex;
|
||||
if (xrot != 0) {
|
||||
line += ",rotx=" + xrot;
|
||||
}
|
||||
if (yrot != 0) {
|
||||
line += ",roty=" + yrot;
|
||||
}
|
||||
if (zrot != 0) {
|
||||
line += ",rotz=" + yrot;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (ModelBlockImpl mb: boxes) {
|
||||
line += String.format(",box=%f/%f/%f:%f/%f/%f", mb.from[0], mb.from[1], mb.from[2], mb.to[0], mb.to[1], mb.to[2]);
|
||||
if ((mb.xrot != 0) || (mb.yrot != 0) || (mb.zrot != 0)) { // If needed, add rotation
|
||||
line += String.format("/%f/%f/%f", mb.xrot, mb.yrot, mb.zrot);
|
||||
}
|
||||
for (BlockSide bs : fromBlockSide.keySet()) {
|
||||
String side = fromBlockSide.get(bs);
|
||||
ModelSide mside = mb.sides.get(bs);
|
||||
if (mside != null) {
|
||||
String rval = side;
|
||||
switch (mside.rot) {
|
||||
case DEG0:
|
||||
default:
|
||||
break;
|
||||
case DEG90:
|
||||
rval += "90";
|
||||
break;
|
||||
case DEG180:
|
||||
rval += "180";
|
||||
break;
|
||||
case DEG270:
|
||||
rval += "270";
|
||||
break;
|
||||
}
|
||||
if (mside.uv != null) {
|
||||
line += String.format(":%s/%d/%f/%f/%f/%f", rval, mside.textureid, mside.uv[0], mside.uv[1], mside.uv[2], mside.uv[3]);
|
||||
}
|
||||
else {
|
||||
line += String.format(":%s/%d", rval, mside.textureid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String line;
|
||||
line = String.format("modellist:%s", ids);
|
||||
for (ModelBlockImpl mb: boxes) {
|
||||
line += String.format(Locale.US, ",box=%f/%f/%f", mb.from[0], mb.from[1], mb.from[2]);
|
||||
if (!mb.shade) { // if shade=false
|
||||
line += "/false";
|
||||
}
|
||||
line += String.format(Locale.US, ":%f/%f/%f", mb.to[0], mb.to[1], mb.to[2]);
|
||||
if ((mb.xrot != 0) || (mb.yrot != 0) || (mb.zrot != 0)) { // If needed, add rotation
|
||||
line += String.format(Locale.US, "/%f/%f/%f", mb.xrot, mb.yrot, mb.zrot);
|
||||
// If origin also defined, add it
|
||||
if (mb.rotorigin != null) {
|
||||
line += String.format(Locale.US, "/%f/%f/%f", mb.rotorigin[0], mb.rotorigin[1], mb.rotorigin[2]);
|
||||
}
|
||||
}
|
||||
for (BlockSide bs : fromBlockSide.keySet()) {
|
||||
String side = fromBlockSide.get(bs);
|
||||
ModelSide mside = mb.sides.get(bs);
|
||||
if (mside != null) {
|
||||
String rval = side;
|
||||
switch (mside.rot) {
|
||||
case DEG0:
|
||||
default:
|
||||
break;
|
||||
case DEG90:
|
||||
rval += "90";
|
||||
break;
|
||||
case DEG180:
|
||||
rval += "180";
|
||||
break;
|
||||
case DEG270:
|
||||
rval += "270";
|
||||
break;
|
||||
}
|
||||
if (mside.uv != null) {
|
||||
line += String.format(Locale.US, ":%s/%d/%f/%f/%f/%f", rval, mside.textureid, mside.uv[0], mside.uv[1], mside.uv[2], mside.uv[3]);
|
||||
}
|
||||
else {
|
||||
line += String.format(":%s/%d", rval, mside.textureid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((mb.modrotx != 0) || (mb.modroty != 0) || (mb.modrotz != 0)) {
|
||||
line += String.format(":R/%d/%d/%d", mb.modrotx, mb.modroty, mb.modrotz);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
@ -135,13 +129,27 @@ public class ModelBlockModelImpl extends BlockModelImpl implements ModelBlockMod
|
|||
* @param xrot - degrees of rotation of block around X
|
||||
* @param yrot - degrees of rotation of block around Y
|
||||
* @param zrot - degrees of rotation of block around Z
|
||||
* @param shade - shade setting for model
|
||||
* @param rotorigin - rotation origin, if any (default [ 8, 8, 8 ](
|
||||
* @param modrotx - model level rotation in degrees (0, 90, 180, 270)
|
||||
* @param modroty - model level rotation in degrees (0, 90, 180, 270)
|
||||
* @param modrotz - model level rotation in degrees (0, 90, 180, 270)
|
||||
* @return model block to add faces to
|
||||
*/
|
||||
public ModelBlock addModelBlock(double[] from, double[] to, double xrot, double yrot, double zrot) {
|
||||
@Override
|
||||
public ModelBlock addModelBlock(double[] from, double[] to, double xrot, double yrot, double zrot,
|
||||
boolean shade, double[] rotorigin, int modrotx, int modroty, int modrotz) {
|
||||
ModelBlockImpl mbi = new ModelBlockImpl();
|
||||
if (from != null) { mbi.from[0] = from[0]; mbi.from[1] = from[1]; mbi.from[2] = from[2]; }
|
||||
if (to != null) { mbi.to[0] = to[0]; mbi.to[1] = to[1]; mbi.to[2] = to[2]; }
|
||||
mbi.xrot = xrot; mbi.yrot = yrot; mbi.zrot = zrot;
|
||||
mbi.shade = shade;
|
||||
if (rotorigin != null) {
|
||||
mbi.rotorigin = Arrays.copyOf(rotorigin, 3);
|
||||
}
|
||||
mbi.modrotx = modrotx;
|
||||
mbi.modroty = modroty;
|
||||
mbi.modrotz = modrotz;
|
||||
boxes.add(mbi);
|
||||
return mbi;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.dynmap.modsupport.PaneBlockModel;
|
|||
|
||||
public class PaneBlockModelImpl extends BlockModelImpl implements PaneBlockModel {
|
||||
|
||||
@Deprecated
|
||||
public PaneBlockModelImpl(int blkid, ModModelDefinitionImpl mdf) {
|
||||
super(blkid, mdf);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.dynmap.renderer.RenderPatchFactory.SideVisible;
|
|||
public class PatchBlockModelImpl extends BlockModelImpl implements PatchBlockModel {
|
||||
private ArrayList<String> patches = new ArrayList<String>();
|
||||
|
||||
@Deprecated
|
||||
public PatchBlockModelImpl(int blkid, ModModelDefinitionImpl mdf) {
|
||||
super(blkid, mdf);
|
||||
}
|
||||
|
@ -15,6 +16,7 @@ public class PatchBlockModelImpl extends BlockModelImpl implements PatchBlockMod
|
|||
super(blkname, mdf);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public PatchBlockModelImpl(int blkid, ModModelDefinitionImpl mdf, PatchBlockModel mod, int xrot, int yrot, int zrot) {
|
||||
super(blkid, mdf);
|
||||
PatchBlockModelImpl m = (PatchBlockModelImpl) mod;
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.dynmap.renderer.RenderPatchFactory.SideVisible;
|
|||
public class PlantBlockModelImpl extends BlockModelImpl implements PlantBlockModel {
|
||||
private String patch0;
|
||||
|
||||
@Deprecated
|
||||
public PlantBlockModelImpl(int blkid, ModModelDefinitionImpl mdf) {
|
||||
super(blkid, mdf);
|
||||
patch0 = mdf.getPatchID(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, SideVisible.FLIP);
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.dynmap.modsupport.StairBlockModel;
|
|||
|
||||
public class StairBlockModelImpl extends BlockModelImpl implements StairBlockModel {
|
||||
|
||||
@Deprecated
|
||||
public StairBlockModelImpl(int blkid, ModModelDefinitionImpl mdf) {
|
||||
super(blkid, mdf);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.dynmap.modsupport.impl;
|
|||
|
||||
import org.dynmap.modsupport.VolumetricBlockModel;
|
||||
|
||||
@Deprecated
|
||||
public class VolumetricBlockModelImpl extends BlockModelImpl implements VolumetricBlockModel {
|
||||
private boolean[][][] grid;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ public class WallFenceBlockModelImpl extends BlockModelImpl implements WallFence
|
|||
private final FenceType type;
|
||||
private int[] linked = new int[0];
|
||||
|
||||
@Deprecated
|
||||
public WallFenceBlockModelImpl(int blkid, ModModelDefinitionImpl mdf, FenceType type) {
|
||||
super(blkid, mdf);
|
||||
this.type = type;
|
||||
|
@ -23,6 +24,7 @@ public class WallFenceBlockModelImpl extends BlockModelImpl implements WallFence
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addLinkedBlockID(int blkid) {
|
||||
int len = linked.length;
|
||||
linked = Arrays.copyOf(linked, len+1);
|
||||
|
@ -30,6 +32,7 @@ public class WallFenceBlockModelImpl extends BlockModelImpl implements WallFence
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int[] getLinkedBlockIDs() {
|
||||
return linked;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.Class;
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package org.dynmap.servlet;
|
|||
|
||||
import org.dynmap.DynmapCore;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.MapType.ImageEncoding;
|
||||
import org.dynmap.PlayerFaces;
|
||||
import org.dynmap.storage.MapStorage;
|
||||
import org.dynmap.storage.MapStorageTile;
|
||||
|
|
|
@ -19,13 +19,15 @@ import javax.servlet.http.HttpSession;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.dynmap.utils.IpAddressMatcher;;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class SendMessageServlet extends HttpServlet {
|
||||
protected static final Logger log = Logger.getLogger("Minecraft");
|
||||
|
@ -50,8 +52,16 @@ public class SendMessageServlet extends HttpServlet {
|
|||
public boolean chat_perms = false;
|
||||
public int lengthlimit = 256;
|
||||
public DynmapCore core;
|
||||
public HashSet<String> proxyaddress = new HashSet<String>();
|
||||
public ArrayList<IpAddressMatcher> proxyaddress = new ArrayList<IpAddressMatcher>();
|
||||
|
||||
private boolean trustedProxy(String ip) {
|
||||
for (IpAddressMatcher m : proxyaddress) {
|
||||
if (m.matches(ip)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
byte[] bytes;
|
||||
|
@ -92,19 +102,13 @@ public class SendMessageServlet extends HttpServlet {
|
|||
if ((message.name == null) || message.name.equals("")) {
|
||||
/* If from trusted proxy, check for client */
|
||||
String rmtaddr = request.getRemoteAddr();
|
||||
if (this.proxyaddress.contains(rmtaddr)) {
|
||||
if (this.trustedProxy(rmtaddr)) { // If remote address is valid trusted proxy
|
||||
/* If proxied client address, get original IP */
|
||||
if (request.getHeader("X-Forwarded-For") != null) {
|
||||
/* If trusted proxies were chained, we get next client address till non-trusted proxy met */
|
||||
String[] proxyAddrs = request.getHeader("X-Forwarded-For").split(", ");
|
||||
for(int i = proxyAddrs.length - 1; i >= 0; i--){
|
||||
if (!this.proxyaddress.contains(proxyAddrs[i])) {
|
||||
/* use remaining addresses as name (maybe we can use the last or the first non-trusted one?) */
|
||||
message.name = proxyAddrs[0]; // 0 .. i
|
||||
for(int j = 1; j <= i; j++) message.name += ", " + proxyAddrs[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Split list, since addresses after first are proxy chain
|
||||
String[] proxyAddrs = request.getHeader("X-Forwarded-For").split(",");
|
||||
// We only want first - any others are proxies that our local proxy was willing to pass to us
|
||||
message.name = proxyAddrs[0].trim();
|
||||
} else {
|
||||
message.name = String.valueOf(o.get("name"));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.dynmap.storage;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
@ -25,13 +26,18 @@ public abstract class MapStorage {
|
|||
private static HashMap<String, Integer> filelocks = new HashMap<String, Integer>();
|
||||
private static final Integer WRITELOCK = (-1);
|
||||
protected File baseStandaloneDir;
|
||||
protected boolean isShutdown;
|
||||
|
||||
protected long serverID;
|
||||
|
||||
protected MapStorage() {
|
||||
this.serverID = 0;
|
||||
this.isShutdown = false;
|
||||
}
|
||||
|
||||
public void shutdownStorage() {
|
||||
this.isShutdown = true;
|
||||
}
|
||||
// Proper modulo - versus the bogus Java behavior of negative modulo for negative numerators
|
||||
protected static final int modulo(int x, int y) {
|
||||
return ((x % y) + y) % y;
|
||||
|
@ -459,7 +465,22 @@ public abstract class MapStorage {
|
|||
|
||||
}
|
||||
|
||||
// Test if storage needs static web files
|
||||
public boolean needsStaticWebFiles() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Set static web file content
|
||||
* @param fileid - file path
|
||||
* @param buffer - content for file
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean setStaticWebFile(String fileid, BufferOutputStream buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void logSQLException(String opmsg, SQLException x) {
|
||||
if (isShutdown) return;
|
||||
Log.severe("SQLException: " + opmsg);
|
||||
Log.severe(" ErrorCode: " + x.getErrorCode() + ", SQLState=" + x.getSQLState());
|
||||
Log.severe(" Message: " + x.getMessage());
|
||||
|
@ -470,4 +491,11 @@ public abstract class MapStorage {
|
|||
cause = cause.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
public static class StorageShutdownException extends Exception {
|
||||
private static final long serialVersionUID = 8961471920726795043L;
|
||||
|
||||
public StorageShutdownException() {}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.dynmap.storage;
|
||||
|
||||
import org.dynmap.MapType.ImageEncoding;
|
||||
|
||||
public interface MapStorageTileSearchEndCB {
|
||||
/**
|
||||
* Callback for end of tile enumeration calls
|
||||
|
|
|
@ -0,0 +1,820 @@
|
|||
package org.dynmap.storage.aws_s3;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.dynmap.DynmapCore;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.MapType;
|
||||
import org.dynmap.MapType.ImageEncoding;
|
||||
import org.dynmap.MapType.ImageVariant;
|
||||
import org.dynmap.PlayerFaces.FaceType;
|
||||
import org.dynmap.WebAuthManager;
|
||||
import org.dynmap.storage.MapStorage;
|
||||
import org.dynmap.storage.MapStorageTile;
|
||||
import org.dynmap.storage.MapStorageTileEnumCB;
|
||||
import org.dynmap.storage.MapStorageBaseTileEnumCB;
|
||||
import org.dynmap.storage.MapStorageTileSearchEndCB;
|
||||
import org.dynmap.utils.BufferInputStream;
|
||||
import org.dynmap.utils.BufferOutputStream;
|
||||
|
||||
import io.github.linktosriram.s3lite.api.client.S3Client;
|
||||
import io.github.linktosriram.s3lite.api.exception.NoSuchKeyException;
|
||||
import io.github.linktosriram.s3lite.api.exception.S3Exception;
|
||||
import io.github.linktosriram.s3lite.api.region.Region;
|
||||
import io.github.linktosriram.s3lite.api.request.DeleteObjectRequest;
|
||||
import io.github.linktosriram.s3lite.api.request.GetObjectRequest;
|
||||
import io.github.linktosriram.s3lite.api.request.ListObjectsV2Request;
|
||||
import io.github.linktosriram.s3lite.api.request.PutObjectRequest;
|
||||
import io.github.linktosriram.s3lite.api.response.GetObjectResponse;
|
||||
import io.github.linktosriram.s3lite.api.response.ListObjectsV2Response;
|
||||
import io.github.linktosriram.s3lite.api.response.ResponseBytes;
|
||||
import io.github.linktosriram.s3lite.api.response.S3Object;
|
||||
import io.github.linktosriram.s3lite.core.auth.AwsBasicCredentials;
|
||||
import io.github.linktosriram.s3lite.core.client.DefaultS3ClientBuilder;
|
||||
import io.github.linktosriram.s3lite.http.spi.request.RequestBody;
|
||||
import io.github.linktosriram.s3lite.http.urlconnection.URLConnectionSdkHttpClient;
|
||||
|
||||
public class AWSS3MapStorage extends MapStorage {
|
||||
public class StorageTile extends MapStorageTile {
|
||||
private final String baseKey;
|
||||
private final String uri;
|
||||
|
||||
StorageTile(DynmapWorld world, MapType map, int x, int y,
|
||||
int zoom, ImageVariant var) {
|
||||
super(world, map, x, y, zoom, var);
|
||||
|
||||
String baseURI;
|
||||
if (zoom > 0) {
|
||||
baseURI = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y;
|
||||
}
|
||||
else {
|
||||
baseURI = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + x + "_" + y;
|
||||
}
|
||||
uri = baseURI + "." + map.getImageFormat().getFileExt();
|
||||
baseKey = AWSS3MapStorage.this.prefix + "tiles/" + world.getName() + "/" + uri;
|
||||
}
|
||||
@Override
|
||||
public boolean exists() {
|
||||
boolean exists = false;
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
ListObjectsV2Request req = ListObjectsV2Request.builder().bucketName(bucketname).prefix(baseKey).maxKeys(1).build();
|
||||
ListObjectsV2Response rslt = s3.listObjectsV2(req);
|
||||
if ((rslt != null) && (rslt.getKeyCount() > 0))
|
||||
exists = true;
|
||||
} catch (S3Exception x) {
|
||||
if (!x.getCode().equals("SignatureDoesNotMatch")) { // S3 behavior when no object match....
|
||||
Log.severe("AWS Exception", x);
|
||||
}
|
||||
} catch (StorageShutdownException x) {
|
||||
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesHashCode(long hash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileRead read() {
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
GetObjectRequest req = GetObjectRequest.builder().bucketName(bucketname).key(baseKey).build();
|
||||
ResponseBytes<GetObjectResponse> obj = s3.getObjectAsBytes(req);
|
||||
if (obj != null) {
|
||||
GetObjectResponse rsp = obj.getResponse();
|
||||
TileRead tr = new TileRead();
|
||||
byte[] buf = obj.getBytes();
|
||||
if (buf == null) { return null; }
|
||||
tr.image = new BufferInputStream(buf);
|
||||
tr.format = ImageEncoding.fromContentType(rsp.getContentType());
|
||||
Map<String, String> meta = rsp.getMetadata();
|
||||
String v = meta.get("x-dynmap-hash");
|
||||
if (v != null) {
|
||||
tr.hashCode = Long.parseLong(v, 16);
|
||||
}
|
||||
v = meta.get("x-dynmap-ts");
|
||||
if (v != null) {
|
||||
tr.lastModified = Long.parseLong(v);
|
||||
}
|
||||
return tr;
|
||||
}
|
||||
} catch (NoSuchKeyException nskx) {
|
||||
return null; // Nominal case if it doesn't exist
|
||||
} catch (S3Exception x) {
|
||||
Log.severe("AWS Exception", x);
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean write(long hash, BufferOutputStream encImage, long timestamp) {
|
||||
boolean done = false;
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
if (encImage == null) { // Delete?
|
||||
DeleteObjectRequest req = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build();
|
||||
s3.deleteObject(req);
|
||||
}
|
||||
else {
|
||||
PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType(map.getImageFormat().getEncoding().getContentType())
|
||||
.addMetadata("x-dynmap-hash", Long.toHexString(hash)).addMetadata("x-dynmap-ts", Long.toString(timestamp)).build();
|
||||
s3.putObject(req, RequestBody.fromBytes(encImage.buf));
|
||||
}
|
||||
done = true;
|
||||
} catch (S3Exception x) {
|
||||
Log.severe("AWS Exception", x);
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
// Signal update for zoom out
|
||||
if (zoom == 0) {
|
||||
world.enqueueZoomOutUpdate(this);
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getWriteLock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseWriteLock() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getReadLock(long timeout) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseReadLock() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURI() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enqueueZoomOutUpdate() {
|
||||
world.enqueueZoomOutUpdate(this);
|
||||
}
|
||||
@Override
|
||||
public MapStorageTile getZoomOutTile() {
|
||||
int xx, yy;
|
||||
int step = 1 << zoom;
|
||||
if(x >= 0)
|
||||
xx = x - (x % (2*step));
|
||||
else
|
||||
xx = x + (x % (2*step));
|
||||
yy = -y;
|
||||
if(yy >= 0)
|
||||
yy = yy - (yy % (2*step));
|
||||
else
|
||||
yy = yy + (yy % (2*step));
|
||||
yy = -yy;
|
||||
return new StorageTile(world, map, xx, yy, zoom+1, var);
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof StorageTile) {
|
||||
StorageTile st = (StorageTile) o;
|
||||
return baseKey.equals(st.baseKey);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return baseKey.hashCode();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return baseKey;
|
||||
}
|
||||
}
|
||||
|
||||
private String bucketname;
|
||||
private Region region;
|
||||
private String access_key_id;
|
||||
private String secret_access_key;
|
||||
private String prefix;
|
||||
|
||||
private int POOLSIZE = 4;
|
||||
private int cpoolCount = 0;
|
||||
private S3Client[] cpool = new S3Client[POOLSIZE];
|
||||
|
||||
public AWSS3MapStorage() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean init(DynmapCore core) {
|
||||
if (!super.init(core)) {
|
||||
return false;
|
||||
}
|
||||
if (!core.isInternalWebServerDisabled) {
|
||||
Log.severe("AWS S3 storage is not supported option with internal web server: set disable-webserver: true in configuration.txt");
|
||||
return false;
|
||||
}
|
||||
if (core.isLoginSupportEnabled()) {
|
||||
Log.severe("AWS S3 storage is not supported option with loegin support enabled: set login-enabled: false in configuration.txt");
|
||||
return false;
|
||||
}
|
||||
// Get our settings
|
||||
bucketname = core.configuration.getString("storage/bucketname", "dynmap");
|
||||
access_key_id = core.configuration.getString("storage/aws_access_key_id", System.getenv("AWS_ACCESS_KEY_ID"));
|
||||
secret_access_key = core.configuration.getString("storage/aws_secret_access_key", System.getenv("AWS_SECRET_ACCESS_KEY"));
|
||||
prefix = core.configuration.getString("storage/prefix", "");
|
||||
|
||||
// Either use a custom region, or one of the default AWS regions
|
||||
String region_name = core.configuration.getString("storage/region", "us-east-1");
|
||||
String region_endpoint = core.configuration.getString("storage/override_endpoint", "");
|
||||
|
||||
if (region_endpoint.length() > 0) {
|
||||
region = Region.of(region_name, URI.create(region_endpoint));
|
||||
} else {
|
||||
region = Region.fromString(region_name);
|
||||
}
|
||||
|
||||
if ((prefix.length() > 0) && (prefix.charAt(prefix.length()-1) != '/')) {
|
||||
prefix += '/';
|
||||
}
|
||||
// Now creste the access client for the S3 service
|
||||
Log.info("Using AWS S3 storage: web site at S3 bucket " + bucketname + " in region " + region);
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
if (s3 == null) {
|
||||
Log.severe("Error creating S3 access client");
|
||||
return false;
|
||||
}
|
||||
// Make sure bucket exists (do list)
|
||||
ListObjectsV2Request listreq = ListObjectsV2Request.builder()
|
||||
.bucketName(bucketname)
|
||||
.maxKeys(1)
|
||||
.prefix(prefix)
|
||||
.build();
|
||||
ListObjectsV2Response rslt = s3.listObjectsV2(listreq);
|
||||
if (rslt == null) {
|
||||
Log.severe("Error: cannot find or access S3 bucket");
|
||||
return false;
|
||||
}
|
||||
rslt.getContents();
|
||||
} catch (S3Exception s3x) {
|
||||
Log.severe("AWS Exception", s3x);
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapStorageTile getTile(DynmapWorld world, MapType map, int x, int y,
|
||||
int zoom, ImageVariant var) {
|
||||
return new StorageTile(world, map, x, y, zoom, var);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapStorageTile getTile(DynmapWorld world, String uri) {
|
||||
String[] suri = uri.split("/");
|
||||
if (suri.length < 2) return null;
|
||||
String mname = suri[0]; // Map URI - might include variant
|
||||
MapType mt = null;
|
||||
ImageVariant imgvar = null;
|
||||
// Find matching map type and image variant
|
||||
for (int mti = 0; (mt == null) && (mti < world.maps.size()); mti++) {
|
||||
MapType type = world.maps.get(mti);
|
||||
ImageVariant[] var = type.getVariants();
|
||||
for (int ivi = 0; (imgvar == null) && (ivi < var.length); ivi++) {
|
||||
if (mname.equals(type.getPrefix() + var[ivi].variantSuffix)) {
|
||||
mt = type;
|
||||
imgvar = var[ivi];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mt == null) { // Not found?
|
||||
return null;
|
||||
}
|
||||
// Now, take the last section and parse out coordinates and zoom
|
||||
String fname = suri[suri.length-1];
|
||||
String[] coord = fname.split("[_\\.]");
|
||||
if (coord.length < 3) { // 3 or 4
|
||||
return null;
|
||||
}
|
||||
int zoom = 0;
|
||||
int x, y;
|
||||
try {
|
||||
if (coord[0].charAt(0) == 'z') {
|
||||
zoom = coord[0].length();
|
||||
x = Integer.parseInt(coord[1]);
|
||||
y = Integer.parseInt(coord[2]);
|
||||
}
|
||||
else {
|
||||
x = Integer.parseInt(coord[0]);
|
||||
y = Integer.parseInt(coord[1]);
|
||||
}
|
||||
return getTile(world, mt, x, y, zoom, imgvar);
|
||||
} catch (NumberFormatException nfx) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb, MapStorageBaseTileEnumCB cbBase,
|
||||
MapStorageTileSearchEndCB cbEnd) {
|
||||
String basekey = prefix + "tiles/" + world.getName() + "/" + map.getPrefix() + var.variantSuffix + "/";
|
||||
ListObjectsV2Request req = ListObjectsV2Request.builder().bucketName(bucketname).prefix(basekey).maxKeys(1000).build();
|
||||
boolean done = false;
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
while (!done) {
|
||||
ListObjectsV2Response result = s3.listObjectsV2(req);
|
||||
List<S3Object> objects = result.getContents();
|
||||
for (S3Object os : objects) {
|
||||
String key = os.getKey();
|
||||
key = key.substring(basekey.length()); // Strip off base
|
||||
// Parse the extension
|
||||
String ext = null;
|
||||
int extoff = key.lastIndexOf('.');
|
||||
if (extoff >= 0) {
|
||||
ext = key.substring(extoff+1);
|
||||
key = key.substring(0, extoff);
|
||||
}
|
||||
// If not valid image extension, ignore
|
||||
ImageEncoding fmt = ImageEncoding.fromExt(ext);
|
||||
if (fmt == null) {
|
||||
continue;
|
||||
}
|
||||
// See if zoom tile: figure out zoom level
|
||||
int zoom = 0;
|
||||
if (key.startsWith("z")) {
|
||||
while (key.startsWith("z")) {
|
||||
key = key.substring(1);
|
||||
zoom++;
|
||||
}
|
||||
if (key.startsWith("_")) {
|
||||
key = key.substring(1);
|
||||
}
|
||||
}
|
||||
// Split remainder to get coords
|
||||
String[] coord = key.split("_");
|
||||
if (coord.length == 2) { // Must be 2 to be a tile
|
||||
try {
|
||||
int x = Integer.parseInt(coord[0]);
|
||||
int y = Integer.parseInt(coord[1]);
|
||||
// Invoke callback
|
||||
MapStorageTile t = new StorageTile(world, map, x, y, zoom, var);
|
||||
if(cb != null)
|
||||
cb.tileFound(t, fmt);
|
||||
if(cbBase != null && t.zoom == 0)
|
||||
cbBase.tileFound(t, fmt);
|
||||
t.cleanup();
|
||||
} catch (NumberFormatException nfx) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.isTruncated()) { // If more, build continuiation request
|
||||
req = ListObjectsV2Request.builder().bucketName(bucketname)
|
||||
.prefix(basekey).delimiter("").maxKeys(1000).continuationToken(result.getContinuationToken()).encodingType("url").requestPayer("requester").build();
|
||||
}
|
||||
else { // Else, we're done
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
} catch (S3Exception x) {
|
||||
if (!x.getCode().equals("SignatureDoesNotMatch")) { // S3 behavior when no object match....
|
||||
Log.severe("AWS Exception", x);
|
||||
Log.severe("req=" + req);
|
||||
}
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
if(cbEnd != null) {
|
||||
cbEnd.searchEnded();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enumMapTiles(DynmapWorld world, MapType map, MapStorageTileEnumCB cb) {
|
||||
List<MapType> mtlist;
|
||||
|
||||
if (map != null) {
|
||||
mtlist = Collections.singletonList(map);
|
||||
}
|
||||
else { // Else, add all directories under world directory (for maps)
|
||||
mtlist = new ArrayList<MapType>(world.maps);
|
||||
}
|
||||
for (MapType mt : mtlist) {
|
||||
ImageVariant[] vars = mt.getVariants();
|
||||
for (ImageVariant var : vars) {
|
||||
processEnumMapTiles(world, mt, var, cb, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
|
||||
List<MapType> mtlist;
|
||||
|
||||
if (map != null) {
|
||||
mtlist = Collections.singletonList(map);
|
||||
}
|
||||
else { // Else, add all directories under world directory (for maps)
|
||||
mtlist = new ArrayList<MapType>(world.maps);
|
||||
}
|
||||
for (MapType mt : mtlist) {
|
||||
ImageVariant[] vars = mt.getVariants();
|
||||
for (ImageVariant var : vars) {
|
||||
processEnumMapTiles(world, mt, var, null, cbBase, cbEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processPurgeMapTiles(DynmapWorld world, MapType map, ImageVariant var) {
|
||||
String basekey = prefix + "tiles/" + world.getName() + "/" + map.getPrefix() + var.variantSuffix + "/";
|
||||
ListObjectsV2Request req = ListObjectsV2Request.builder().bucketName(bucketname).prefix(basekey).delimiter("").maxKeys(1000).encodingType("url").requestPayer("requester").build();
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
ListObjectsV2Response result = s3.listObjectsV2(req);
|
||||
List<S3Object> objects = result.getContents();
|
||||
for (S3Object os : objects) {
|
||||
String key = os.getKey();
|
||||
DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(key).build();
|
||||
s3.deleteObject(delreq);
|
||||
}
|
||||
if (result.isTruncated()) { // If more, build continuiation request
|
||||
req = ListObjectsV2Request.builder().bucketName(bucketname)
|
||||
.prefix(basekey).delimiter("").maxKeys(1000).continuationToken(result.getContinuationToken()).encodingType("url").requestPayer("requester").build();
|
||||
}
|
||||
else { // Else, we're done
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
} catch (S3Exception x) {
|
||||
if (!x.getCode().equals("SignatureDoesNotMatch")) { // S3 behavior when no object match....
|
||||
Log.severe("AWS Exception", x);
|
||||
Log.severe("req=" + req);
|
||||
}
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purgeMapTiles(DynmapWorld world, MapType map) {
|
||||
List<MapType> mtlist;
|
||||
|
||||
if (map != null) {
|
||||
mtlist = Collections.singletonList(map);
|
||||
}
|
||||
else { // Else, add all directories under world directory (for maps)
|
||||
mtlist = new ArrayList<MapType>(world.maps);
|
||||
}
|
||||
for (MapType mt : mtlist) {
|
||||
ImageVariant[] vars = mt.getVariants();
|
||||
for (ImageVariant var : vars) {
|
||||
processPurgeMapTiles(world, mt, var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setPlayerFaceImage(String playername, FaceType facetype,
|
||||
BufferOutputStream encImage) {
|
||||
boolean done = false;
|
||||
String baseKey = prefix + "tiles/faces/" + facetype.id + "/" + playername + ".png";
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
if (encImage == null) { // Delete?
|
||||
DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build();
|
||||
s3.deleteObject(delreq);
|
||||
}
|
||||
else {
|
||||
PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType("image/png").build();
|
||||
s3.putObject(req, RequestBody.fromBytes(encImage.buf));
|
||||
}
|
||||
done = true;
|
||||
} catch (S3Exception x) {
|
||||
Log.severe("AWS Exception", x);
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferInputStream getPlayerFaceImage(String playername,
|
||||
FaceType facetype) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPlayerFaceImage(String playername, FaceType facetype) {
|
||||
String baseKey = prefix + "tiles/faces/" + facetype.id + "/" + playername + ".png";
|
||||
boolean exists = false;
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
ListObjectsV2Request req = ListObjectsV2Request.builder().bucketName(bucketname).prefix(baseKey).maxKeys(1).build();
|
||||
ListObjectsV2Response rslt = s3.listObjectsV2(req);
|
||||
if ((rslt != null) && (rslt.getKeyCount() > 0))
|
||||
exists = true;
|
||||
} catch (S3Exception x) {
|
||||
if (!x.getCode().equals("SignatureDoesNotMatch")) { // S3 behavior when no object match....
|
||||
Log.severe("AWS Exception", x);
|
||||
}
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMarkerImage(String markerid, BufferOutputStream encImage) {
|
||||
boolean done = false;
|
||||
String baseKey = prefix + "tiles/_markers_/" + markerid + ".png";
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
if (encImage == null) { // Delete?
|
||||
DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build();
|
||||
s3.deleteObject(delreq);
|
||||
}
|
||||
else {
|
||||
PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType("image/png").build();
|
||||
s3.putObject(req, RequestBody.fromBytes(encImage.buf));
|
||||
}
|
||||
done = true;
|
||||
} catch (S3Exception x) {
|
||||
Log.severe("AWS Exception", x);
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferInputStream getMarkerImage(String markerid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMarkerFile(String world, String content) {
|
||||
boolean done = false;
|
||||
String baseKey = prefix + "tiles/_markers_/marker_" + world + ".json";
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
if (content == null) { // Delete?
|
||||
DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build();
|
||||
s3.deleteObject(delreq);
|
||||
}
|
||||
else {
|
||||
PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType("application/json").build();
|
||||
s3.putObject(req, RequestBody.fromBytes(content.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
done = true;
|
||||
} catch (S3Exception x) {
|
||||
Log.severe("AWS Exception", x);
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMarkerFile(String world) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
// For external web server only
|
||||
public String getMarkersURI(boolean login_enabled) {
|
||||
return "tiles/";
|
||||
}
|
||||
|
||||
@Override
|
||||
// For external web server only
|
||||
public String getTilesURI(boolean login_enabled) {
|
||||
return "tiles/";
|
||||
}
|
||||
|
||||
/**
|
||||
* URI to use for loading configuration JSON files (for external web server only)
|
||||
* @param login_enabled - selects based on login security enabled
|
||||
* @return URI
|
||||
*/
|
||||
public String getConfigurationJSONURI(boolean login_enabled) {
|
||||
return "standalone/dynmap_config.json?_={timestamp}";
|
||||
}
|
||||
/**
|
||||
* URI to use for loading update JSON files (for external web server only)
|
||||
* @param login_enabled - selects based on login security enabled
|
||||
* @return URI
|
||||
*/
|
||||
public String getUpdateJSONURI(boolean login_enabled) {
|
||||
return "standalone/dynmap_{world}.json?_={timestamp}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPaths(StringBuilder sb, DynmapCore core) {
|
||||
String p = core.getTilesFolder().getAbsolutePath();
|
||||
if(!p.endsWith("/"))
|
||||
p += "/";
|
||||
sb.append("$tilespath = \'");
|
||||
sb.append(WebAuthManager.esc(p));
|
||||
sb.append("\';\n");
|
||||
sb.append("$markerspath = \'");
|
||||
sb.append(WebAuthManager.esc(p));
|
||||
sb.append("\';\n");
|
||||
|
||||
// Need to call base to add webpath
|
||||
super.addPaths(sb, core);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BufferInputStream getStandaloneFile(String fileid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Cache to avoid rewriting same standalong file repeatedly
|
||||
private ConcurrentHashMap<String, byte[]> standalone_cache = new ConcurrentHashMap<String, byte[]>();
|
||||
|
||||
@Override
|
||||
public boolean setStandaloneFile(String fileid, BufferOutputStream content) {
|
||||
return setStaticWebFile("standalone/" + fileid, content);
|
||||
}
|
||||
// Test if storage needs static web files
|
||||
public boolean needsStaticWebFiles() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Set static web file content
|
||||
* @param fileid - file path
|
||||
* @param content - content for file
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean setStaticWebFile(String fileid, BufferOutputStream content) {
|
||||
|
||||
boolean done = false;
|
||||
String baseKey = prefix + fileid;
|
||||
S3Client s3 = null;
|
||||
try {
|
||||
s3 = getConnection();
|
||||
byte[] cacheval = standalone_cache.get(fileid);
|
||||
|
||||
if (content == null) { // Delete?
|
||||
if ((cacheval != null) && (cacheval.length == 0)) { // Delete cached?
|
||||
return true;
|
||||
}
|
||||
DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build();
|
||||
s3.deleteObject(delreq);
|
||||
standalone_cache.put(fileid, new byte[0]); // Mark in cache
|
||||
}
|
||||
else {
|
||||
byte[] digest = content.buf;
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.update(content.buf);
|
||||
digest = md.digest();
|
||||
} catch (NoSuchAlgorithmException nsax) {
|
||||
|
||||
}
|
||||
// If cached and same, just return
|
||||
if (Arrays.equals(digest, cacheval)) {
|
||||
return true;
|
||||
}
|
||||
String ct = "text/plain";
|
||||
if (fileid.endsWith(".json")) {
|
||||
ct = "application/json";
|
||||
}
|
||||
else if (fileid.endsWith(".php")) {
|
||||
ct = "application/x-httpd-php";
|
||||
}
|
||||
else if (fileid.endsWith(".html")) {
|
||||
ct = "text/html";
|
||||
}
|
||||
else if (fileid.endsWith(".css")) {
|
||||
ct = "text/css";
|
||||
}
|
||||
else if (fileid.endsWith(".js")) {
|
||||
ct = "application/x-javascript";
|
||||
}
|
||||
PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType(ct).build();
|
||||
s3.putObject(req, RequestBody.fromBytes(content.buf));
|
||||
standalone_cache.put(fileid, digest);
|
||||
}
|
||||
done = true;
|
||||
} catch (S3Exception x) {
|
||||
Log.severe("AWS Exception", x);
|
||||
} catch (StorageShutdownException x) {
|
||||
} finally {
|
||||
releaseConnection(s3);
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
private S3Client getConnection() throws S3Exception, StorageShutdownException {
|
||||
S3Client c = null;
|
||||
if (isShutdown) throw new StorageShutdownException();
|
||||
synchronized (cpool) {
|
||||
while (c == null) {
|
||||
for (int i = 0; i < cpool.length; i++) { // See if available connection
|
||||
if (cpool[i] != null) { // Found one
|
||||
c = cpool[i];
|
||||
cpool[i] = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == null) {
|
||||
if (cpoolCount < POOLSIZE) { // Still more we can have
|
||||
c = new DefaultS3ClientBuilder()
|
||||
.credentialsProvider(() -> AwsBasicCredentials.create(access_key_id, secret_access_key))
|
||||
.region(region)
|
||||
.httpClient(URLConnectionSdkHttpClient.create())
|
||||
.build();
|
||||
if (c == null) {
|
||||
Log.severe("Error creating S3 access client");
|
||||
return null;
|
||||
}
|
||||
cpoolCount++;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
cpool.wait();
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private void releaseConnection(S3Client c) {
|
||||
if (c == null) return;
|
||||
synchronized (cpool) {
|
||||
for (int i = 0; i < POOLSIZE; i++) {
|
||||
if (cpool[i] == null) {
|
||||
cpool[i] = c;
|
||||
c = null; // Mark it recovered (no close needed
|
||||
cpool.notifyAll();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c != null) { // If broken, just toss it
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
cpoolCount--; // And reduce count
|
||||
cpool.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ public class FileTreeMapStorage extends MapStorage {
|
|||
super(world, map, x, y, zoom, var);
|
||||
String baseURI;
|
||||
if (zoom > 0) {
|
||||
baseURI = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y;
|
||||
baseURI = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y;
|
||||
}
|
||||
else {
|
||||
baseURI = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + x + "_" + y;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,6 +5,7 @@ import java.io.FileWriter;
|
|||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -48,6 +49,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
protected int port;
|
||||
private static final int POOLSIZE = 5;
|
||||
private Connection[] cpool = new Connection[POOLSIZE];
|
||||
private long[] cpoolLastUseTS = new long[POOLSIZE]; // Time when last returned to pool
|
||||
private static final long IDLE_TIMEOUT = 60000; // Use 60 second timeout
|
||||
private int cpoolCount = 0;
|
||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
|
@ -61,7 +64,7 @@ public class MySQLMapStorage extends MapStorage {
|
|||
mapkey = getMapKey(world, map, var);
|
||||
|
||||
if (zoom > 0) {
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
}
|
||||
else {
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
|
@ -84,6 +87,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile exists error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -109,6 +114,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile matches hash error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -132,13 +139,19 @@ public class MySQLMapStorage extends MapStorage {
|
|||
rslt.format = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
|
||||
byte[] img = rs.getBytes("NewImage");
|
||||
if (img == null) img = rs.getBytes("Image");
|
||||
rslt.image = new BufferInputStream(img);
|
||||
if (img == null) {
|
||||
rslt = null;
|
||||
} else {
|
||||
rslt.image = new BufferInputStream(img);
|
||||
}
|
||||
}
|
||||
rs.close();
|
||||
stmt.close();
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Tile read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -195,6 +208,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -370,6 +385,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
Connection c = null;
|
||||
try {
|
||||
c = getConnection(); // Get connection (create DB if needed)
|
||||
DatabaseMetaData md = c.getMetaData();
|
||||
Log.info("Connected to " + md.getDatabaseProductName() + " v" + md.getDatabaseMajorVersion() + "." + md.getDatabaseMinorVersion());
|
||||
Statement stmt = c.createStatement();
|
||||
ResultSet rs = stmt.executeQuery( "SELECT level FROM " + tableSchemaVersion + ";");
|
||||
if (rs.next()) {
|
||||
|
@ -379,6 +396,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
stmt.close();
|
||||
} catch (SQLException x) {
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (c != null) { releaseConnection(c, err); }
|
||||
}
|
||||
|
@ -418,6 +437,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Error loading map table", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -457,6 +478,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Error updating Maps table", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -481,13 +504,17 @@ public class MySQLMapStorage extends MapStorage {
|
|||
doUpdate(c, "CREATE TABLE " + tableMarkerIcons + " (IconName VARCHAR(128) PRIMARY KEY NOT NULL, Image MEDIUMBLOB)");
|
||||
doUpdate(c, "CREATE TABLE " + tableMarkerFiles + " (FileName VARCHAR(128) PRIMARY KEY NOT NULL, Content MEDIUMTEXT)");
|
||||
doUpdate(c, "CREATE TABLE " + tableStandaloneFiles + " (FileName VARCHAR(128) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0, Content MEDIUMTEXT, PRIMARY KEY (FileName, ServerID))");
|
||||
doUpdate(c, "CREATE INDEX " + tableMaps + "_idx ON " + tableMaps + "(WorldID, MapID, Variant, ServerID)");
|
||||
doUpdate(c, "CREATE TABLE " + tableSchemaVersion + " (level INT PRIMARY KEY NOT NULL)");
|
||||
doUpdate(c, "INSERT INTO " + tableSchemaVersion + " (level) VALUES (5)");
|
||||
version = 5; // Initial - we have all the following updates already
|
||||
doUpdate(c, "INSERT INTO " + tableSchemaVersion + " (level) VALUES (6)");
|
||||
version = 6; // Initial - we have all the following updates already
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error creating tables", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -502,9 +529,12 @@ public class MySQLMapStorage extends MapStorage {
|
|||
doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=2 WHERE level = 1;");
|
||||
version = 2;
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error updating tables to version=1", x);
|
||||
logSQLException("Error updating tables to version=2", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -520,9 +550,12 @@ public class MySQLMapStorage extends MapStorage {
|
|||
doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=3 WHERE level = 2;");
|
||||
version = 3;
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error updating tables to version=2", x);
|
||||
logSQLException("Error updating tables to version=3", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -538,9 +571,12 @@ public class MySQLMapStorage extends MapStorage {
|
|||
doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=4 WHERE level = 3;");
|
||||
version = 4;
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error updating tables to version=3", x);
|
||||
logSQLException("Error updating tables to version=4", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -550,6 +586,7 @@ public class MySQLMapStorage extends MapStorage {
|
|||
try {
|
||||
Log.info("Updating database schema from version = " + version);
|
||||
c = getConnection();
|
||||
DatabaseMetaData md = c.getMetaData();
|
||||
// See if we are recovering from bug where version was still set to 4 when NewImage was added initialli
|
||||
PreparedStatement stmt = c.prepareStatement("SHOW COLUMNS FROM " + tableTiles + " WHERE Field = 'NewImage';");
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
|
@ -560,14 +597,42 @@ public class MySQLMapStorage extends MapStorage {
|
|||
rs.close();
|
||||
stmt.close();
|
||||
if (!inplace) {
|
||||
doUpdate(c, "ALTER TABLE " + tableTiles + " ADD COLUMN NewImage MEDIUMBLOB, ALGORITHM=INPLACE, LOCK=NONE");
|
||||
try {
|
||||
doUpdate(c, "ALTER TABLE " + tableTiles + " ADD COLUMN NewImage MEDIUMBLOB, ALGORITHM=INPLACE, LOCK=NONE");
|
||||
} catch (SQLException x) {
|
||||
Log.info("Updating tiles table using legacy method - this might take a while and may need a lot of database space...");
|
||||
doUpdate(c, "ALTER TABLE " + tableTiles + " ADD COLUMN NewImage MEDIUMBLOB");
|
||||
Log.info("Legacy tile update completed");
|
||||
}
|
||||
}
|
||||
doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=5 WHERE level = 4;");
|
||||
version = 5;
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error updating tables to version=3", x);
|
||||
logSQLException("Error updating tables to version=5", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
}
|
||||
}
|
||||
if (version == 5) {
|
||||
try {
|
||||
Log.info("Updating database schema from version = " + version);
|
||||
c = getConnection();
|
||||
doUpdate(c, "CREATE INDEX " + tableMaps + "_idx ON " + tableMaps + "(WorldID, MapID, Variant, ServerID)");
|
||||
doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=6 WHERE level = 5;");
|
||||
version = 6;
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error updating tables to version=5", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -580,15 +645,26 @@ public class MySQLMapStorage extends MapStorage {
|
|||
return true;
|
||||
}
|
||||
|
||||
private Connection getConnection() throws SQLException {
|
||||
private Connection getConnection() throws SQLException, StorageShutdownException {
|
||||
Connection c = null;
|
||||
if (isShutdown) { throw new StorageShutdownException(); }
|
||||
synchronized (cpool) {
|
||||
long now = System.currentTimeMillis();
|
||||
while (c == null) {
|
||||
for (int i = 0; i < cpool.length; i++) { // See if available connection
|
||||
if (cpool[i] != null) { // Found one
|
||||
c = cpool[i];
|
||||
cpool[i] = null;
|
||||
break;
|
||||
// If in pool too long, close it and move on
|
||||
if ((now - cpoolLastUseTS[i]) > IDLE_TIMEOUT) {
|
||||
try { cpool[i].close(); } catch (SQLException x) {}
|
||||
cpool[i] = null;
|
||||
cpoolCount--;
|
||||
}
|
||||
else { // Else, use the connection
|
||||
c = cpool[i];
|
||||
cpool[i] = null;
|
||||
cpoolLastUseTS[i] = now;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c == null) {
|
||||
|
@ -621,6 +697,7 @@ public class MySQLMapStorage extends MapStorage {
|
|||
for (int i = 0; i < POOLSIZE; i++) {
|
||||
if (cpool[i] == null) {
|
||||
cpool[i] = c;
|
||||
cpoolLastUseTS[i] = System.currentTimeMillis(); // Record last use time
|
||||
c = null; // Mark it recovered (no close needed
|
||||
cpool.notifyAll();
|
||||
break;
|
||||
|
@ -732,9 +809,10 @@ public class MySQLMapStorage extends MapStorage {
|
|||
}
|
||||
try {
|
||||
c = getConnection();
|
||||
// Query tiles for given mapkey
|
||||
Statement stmt = c.createStatement();
|
||||
ResultSet rs = stmt.executeQuery("SELECT x,y,zoom,Format FROM " + tableTiles + " WHERE MapID=" + mapkey + ";");
|
||||
Statement stmt = c.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, //we want to stream our resultset one row at a time, we are not interessted in going back
|
||||
java.sql.ResultSet.CONCUR_READ_ONLY); //since we do not handle the entire resultset in memory -> tell the statement that we are going to work read only
|
||||
stmt.setFetchSize(100); //we can change the jdbc "retrieval chunk size". Basicly we limit how much rows are kept in memory. Bigger value = less network calls to DB, but more memory consumption
|
||||
ResultSet rs = stmt.executeQuery(String.format("SELECT x,y,zoom,Format FROM %s WHERE MapID=%d;", tableTiles, mapkey)); //we do the query, but do not set any limit / offset. Since data is not kept in memory, just streamed from DB this should not be a problem, only the rows from setFetchSize are kept in memory.
|
||||
while (rs.next()) {
|
||||
StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var);
|
||||
final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
|
||||
|
@ -744,13 +822,15 @@ public class MySQLMapStorage extends MapStorage {
|
|||
cbBase.tileFound(st, encoding);
|
||||
st.cleanup();
|
||||
}
|
||||
if(cbEnd != null)
|
||||
cbEnd.searchEnded();
|
||||
rs.close();
|
||||
stmt.close();
|
||||
if(cbEnd != null)
|
||||
cbEnd.searchEnded();
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Tile enum error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -789,6 +869,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile purge error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -828,6 +910,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -855,6 +939,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face reqd error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -880,6 +966,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face exists error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -927,6 +1015,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (rs != null) { try { rs.close(); } catch (SQLException sx) {} }
|
||||
if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} }
|
||||
|
@ -954,6 +1044,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -1000,6 +1092,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker file write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (rs != null) { try { rs.close(); } catch (SQLException sx) {} }
|
||||
if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} }
|
||||
|
@ -1027,6 +1121,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker file read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -1083,6 +1179,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Standalone file read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -1133,6 +1231,8 @@ public class MySQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Standalone file write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (rs != null) { try { rs.close(); } catch (SQLException sx) {} }
|
||||
if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} }
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.dynmap.storage.MapStorageBaseTileEnumCB;
|
|||
import org.dynmap.storage.MapStorageTile;
|
||||
import org.dynmap.storage.MapStorageTileEnumCB;
|
||||
import org.dynmap.storage.MapStorageTileSearchEndCB;
|
||||
import org.dynmap.storage.mysql.MySQLMapStorage.StorageTile;
|
||||
import org.dynmap.utils.BufferInputStream;
|
||||
import org.dynmap.utils.BufferOutputStream;
|
||||
|
||||
|
@ -50,6 +49,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
private int port;
|
||||
private static final int POOLSIZE = 5;
|
||||
private Connection[] cpool = new Connection[POOLSIZE];
|
||||
private long[] cpoolLastUseTS = new long[POOLSIZE]; // Time when last returned to pool
|
||||
private static final long IDLE_TIMEOUT = 60000; // Use 60 second timeout
|
||||
private int cpoolCount = 0;
|
||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
|
@ -65,7 +66,7 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
mapkey = getMapKey(world, map, var);
|
||||
|
||||
if (zoom > 0) {
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
}
|
||||
else {
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
|
@ -88,6 +89,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile exists error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -113,6 +116,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile matches hash error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -135,13 +140,19 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
rslt.lastModified = rs.getLong("LastUpdate");
|
||||
rslt.format = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
|
||||
byte[] img = rs.getBytes("Image");
|
||||
rslt.image = new BufferInputStream(img);
|
||||
if (img == null) {
|
||||
rslt = null;
|
||||
} else {
|
||||
rslt.image = new BufferInputStream(img);
|
||||
}
|
||||
}
|
||||
rs.close();
|
||||
stmt.close();
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Tile read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -198,6 +209,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -367,6 +380,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
stmt.close();
|
||||
} catch (SQLException x) {
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (c != null) { releaseConnection(c, err); }
|
||||
}
|
||||
|
@ -404,6 +419,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Error loading map table", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -443,6 +460,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Error updating Maps table", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -467,13 +486,17 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
doUpdate(c, "CREATE TABLE " + tableMarkerIcons + " (IconName VARCHAR(128) PRIMARY KEY NOT NULL, Image BYTEA)");
|
||||
doUpdate(c, "CREATE TABLE " + tableMarkerFiles + " (FileName VARCHAR(128) PRIMARY KEY NOT NULL, Content BYTEA)");
|
||||
doUpdate(c, "CREATE TABLE " + tableStandaloneFiles + " (FileName VARCHAR(128) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0, Content BYTEA, PRIMARY KEY (FileName, ServerID))");
|
||||
doUpdate(c, "CREATE INDEX " + tableMaps + "_idx ON " + tableMaps + "(WorldID, MapID, Variant, ServerID)");
|
||||
doUpdate(c, "CREATE TABLE " + tableSchemaVersion + " (level INT PRIMARY KEY NOT NULL)");
|
||||
doUpdate(c, "INSERT INTO " + tableSchemaVersion + " (level) VALUES (3)");
|
||||
version = 3; // initialzed to current schema
|
||||
doUpdate(c, "INSERT INTO " + tableSchemaVersion + " (level) VALUES (4)");
|
||||
version = 4; // initialzed to current schema
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error creating tables", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -491,6 +514,9 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
logSQLException("Error upgrading tables to version=2", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -509,6 +535,28 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
logSQLException("Error upgrading tables to version=3", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
}
|
||||
}
|
||||
if (version == 3) {
|
||||
try {
|
||||
Log.info("Updating database schema from version = " + version);
|
||||
c = getConnection();
|
||||
doUpdate(c, "CREATE INDEX " + tableMaps + "_idx ON " + tableMaps + "(WorldID, MapID, Variant, ServerID)");
|
||||
doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=4 WHERE level = 3;");
|
||||
version = 4;
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error upgrading tables to version=4", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -521,15 +569,26 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
return true;
|
||||
}
|
||||
|
||||
private Connection getConnection() throws SQLException {
|
||||
private Connection getConnection() throws SQLException, StorageShutdownException {
|
||||
Connection c = null;
|
||||
if (isShutdown) throw new StorageShutdownException();
|
||||
synchronized (cpool) {
|
||||
long now = System.currentTimeMillis();
|
||||
while (c == null) {
|
||||
for (int i = 0; i < cpool.length; i++) { // See if available connection
|
||||
if (cpool[i] != null) { // Found one
|
||||
c = cpool[i];
|
||||
cpool[i] = null;
|
||||
break;
|
||||
// If in pool too long, close it and move on
|
||||
if ((now - cpoolLastUseTS[i]) > IDLE_TIMEOUT) {
|
||||
try { cpool[i].close(); } catch (SQLException x) {}
|
||||
cpool[i] = null;
|
||||
cpoolCount--;
|
||||
}
|
||||
else { // Else, use the connection
|
||||
c = cpool[i];
|
||||
cpool[i] = null;
|
||||
cpoolLastUseTS[i] = now;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c == null) {
|
||||
|
@ -561,6 +620,7 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
for (int i = 0; i < POOLSIZE; i++) {
|
||||
if (cpool[i] == null) {
|
||||
cpool[i] = c;
|
||||
cpoolLastUseTS[i] = System.currentTimeMillis(); // Record last use time
|
||||
c = null; // Mark it recovered (no close needed
|
||||
cpool.notifyAll();
|
||||
break;
|
||||
|
@ -655,25 +715,36 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
}
|
||||
try {
|
||||
c = getConnection();
|
||||
// Query tiles for given mapkey
|
||||
Statement stmt = c.createStatement();
|
||||
ResultSet rs = stmt.executeQuery("SELECT x,y,zoom,Format FROM " + tableTiles + " WHERE MapID=" + mapkey + ";");
|
||||
while (rs.next()) {
|
||||
StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var);
|
||||
final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
|
||||
if(cb != null)
|
||||
cb.tileFound(st, encoding);
|
||||
if(cbBase != null && st.zoom == 0)
|
||||
cbBase.tileFound(st, encoding);
|
||||
st.cleanup();
|
||||
boolean done = false;
|
||||
int offset = 0;
|
||||
int limit = 100;
|
||||
while (!done) {
|
||||
// Query tiles for given mapkey
|
||||
Statement stmt = c.createStatement();
|
||||
ResultSet rs = stmt.executeQuery(String.format("SELECT x,y,zoom,Format FROM %s WHERE MapID=%d OFFSET %d LIMIT %d;", tableTiles, mapkey, offset, limit));
|
||||
int cnt = 0;
|
||||
while (rs.next()) {
|
||||
StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var);
|
||||
final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
|
||||
if(cb != null)
|
||||
cb.tileFound(st, encoding);
|
||||
if(cbBase != null && st.zoom == 0)
|
||||
cbBase.tileFound(st, encoding);
|
||||
st.cleanup();
|
||||
cnt++;
|
||||
}
|
||||
rs.close();
|
||||
stmt.close();
|
||||
if (cnt < limit) done = true;
|
||||
offset += cnt;
|
||||
}
|
||||
if(cbEnd != null)
|
||||
cbEnd.searchEnded();
|
||||
rs.close();
|
||||
stmt.close();
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Tile enum error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -728,6 +799,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile purge error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -767,6 +840,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -794,6 +869,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -819,6 +896,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face exists error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -866,6 +945,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (rs != null) { try { rs.close(); } catch (SQLException sx) {} }
|
||||
if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} }
|
||||
|
@ -893,6 +974,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -939,6 +1022,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker file write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (rs != null) { try { rs.close(); } catch (SQLException sx) {} }
|
||||
if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} }
|
||||
|
@ -966,6 +1051,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker file read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -1022,6 +1109,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Standalone file read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -1072,6 +1161,8 @@ public class PostgreSQLMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Standalone file write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (rs != null) { try { rs.close(); } catch (SQLException sx) {} }
|
||||
if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} }
|
||||
|
|
|
@ -31,8 +31,10 @@ import org.dynmap.utils.BufferOutputStream;
|
|||
public class SQLiteMapStorage extends MapStorage {
|
||||
private String connectionString;
|
||||
private String databaseFile;
|
||||
private static final int POOLSIZE = 5;
|
||||
private static final int POOLSIZE = 1; // SQLite is really not thread safe... 1 at a time works best
|
||||
private Connection[] cpool = new Connection[POOLSIZE];
|
||||
private long[] cpoolLastUseTS = new long[POOLSIZE]; // Time when last returned to pool
|
||||
private static final long IDLE_TIMEOUT = 60000; // Use 60 second timeout
|
||||
private int cpoolCount = 0;
|
||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
|
@ -46,7 +48,7 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
mapkey = getMapKey(world, map, var);
|
||||
|
||||
if (zoom > 0) {
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
}
|
||||
else {
|
||||
uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + x + "_" + y + "." + map.getImageFormat().getFileExt();
|
||||
|
@ -70,6 +72,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile exists error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -96,6 +100,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile matches hash error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -125,13 +131,19 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
// Trim trailing zeros from padding by BLOB field
|
||||
while((len > 0) && (img[len-1] == '\0')) len--;
|
||||
}
|
||||
rslt.image = new BufferInputStream(img, len);
|
||||
if (img == null) {
|
||||
rslt = null;
|
||||
} else {
|
||||
rslt.image = new BufferInputStream(img, len);
|
||||
}
|
||||
}
|
||||
rs.close();
|
||||
stmt.close();
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Tile read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -191,6 +203,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -269,6 +283,7 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
@Override
|
||||
public boolean init(DynmapCore core) {
|
||||
if (!super.init(core)) {
|
||||
isShutdown = true;
|
||||
return false;
|
||||
}
|
||||
File dbfile = core.getFile(core.configuration.getString("storage/dbfile", "dynmap.db"));
|
||||
|
@ -281,6 +296,7 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
return initializeTables();
|
||||
} catch (ClassNotFoundException cnfx) {
|
||||
Log.severe("SQLite-JDBC classes not found - sqlite data source not usable");
|
||||
isShutdown = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -301,6 +317,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
stmt.close();
|
||||
} catch (SQLException x) {
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (c != null) { releaseConnection(c, err); }
|
||||
}
|
||||
|
@ -339,6 +357,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Error loading map table", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -378,6 +398,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Error updating Maps table", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -401,13 +423,18 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
doUpdate(c, "CREATE TABLE Faces (PlayerName STRING NOT NULL, TypeID INT NOT NULL, Image BLOB, ImageLen INT, PRIMARY KEY(PlayerName, TypeID))");
|
||||
doUpdate(c, "CREATE TABLE MarkerIcons (IconName STRING PRIMARY KEY NOT NULL, Image BLOB, ImageLen INT)");
|
||||
doUpdate(c, "CREATE TABLE MarkerFiles (FileName STRING PRIMARY KEY NOT NULL, Content CLOB)");
|
||||
// Add index, since SQLite execution planner is stupid and scans Tiles table instead of using short Maps table...
|
||||
doUpdate(c, "CREATE INDEX MapIndex ON Maps(WorldID, MapID, Variant)");
|
||||
doUpdate(c, "CREATE TABLE SchemaVersion (level INT PRIMARY KEY NOT NULL)");
|
||||
doUpdate(c, "INSERT INTO SchemaVersion (level) VALUES (2)");
|
||||
version = 2; // Initializes to current schema
|
||||
doUpdate(c, "INSERT INTO SchemaVersion (level) VALUES (3)");
|
||||
version = 3; // Initializes to current schema
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error creating tables", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -426,6 +453,29 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
logSQLException("Error updating tables to version=2", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
}
|
||||
}
|
||||
if (version == 2) {
|
||||
try {
|
||||
Log.info("Updating database schema from version = " + version);
|
||||
c = getConnection();
|
||||
// Add index, since SQLite execution planner is stupid and scans Tiles table instead of using short Maps table...
|
||||
doUpdate(c, "CREATE INDEX MapIndex ON Maps(WorldID, MapID, Variant)");
|
||||
doUpdate(c, "UPDATE SchemaVersion SET level=3");
|
||||
version = 2;
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Error updating tables to version=3", x);
|
||||
err = true;
|
||||
return false;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
return false;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
|
@ -438,14 +488,28 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
return true;
|
||||
}
|
||||
|
||||
private Connection getConnection() throws SQLException {
|
||||
private Connection getConnection() throws SQLException, StorageShutdownException {
|
||||
Connection c = null;
|
||||
if (isShutdown) {
|
||||
throw new StorageShutdownException();
|
||||
}
|
||||
synchronized (cpool) {
|
||||
long now = System.currentTimeMillis();
|
||||
while (c == null) {
|
||||
for (int i = 0; i < cpool.length; i++) { // See if available connection
|
||||
if (cpool[i] != null) { // Found one
|
||||
c = cpool[i];
|
||||
cpool[i] = null;
|
||||
// If in pool too long, close it and move on
|
||||
if ((now - cpoolLastUseTS[i]) > IDLE_TIMEOUT) {
|
||||
try { cpool[i].close(); } catch (SQLException x) {}
|
||||
cpool[i] = null;
|
||||
cpoolCount--;
|
||||
}
|
||||
else { // Else, use the connection
|
||||
c = cpool[i];
|
||||
cpool[i] = null;
|
||||
cpoolLastUseTS[i] = now;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c == null) {
|
||||
|
@ -469,6 +533,7 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
|
||||
private static Connection configureConnection(Connection conn) throws SQLException {
|
||||
final Statement statement = conn.createStatement();
|
||||
statement.execute("PRAGMA auto_vacuum = FULL;");
|
||||
statement.execute("PRAGMA journal_mode = WAL;");
|
||||
statement.close();
|
||||
return conn;
|
||||
|
@ -481,6 +546,7 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
for (int i = 0; i < POOLSIZE; i++) {
|
||||
if (cpool[i] == null) {
|
||||
cpool[i] = c;
|
||||
cpoolLastUseTS[i] = System.currentTimeMillis(); // Record last use time
|
||||
c = null; // Mark it recovered (no close needed
|
||||
cpool.notifyAll();
|
||||
break;
|
||||
|
@ -593,27 +659,39 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
c = getConnection();
|
||||
// Query tiles for given mapkey
|
||||
Statement stmt = c.createStatement();
|
||||
//ResultSet rs = stmt.executeQuery("SELECT x,y,zoom,Format FROM Tiles WHERE MapID=" + mapkey + ";");
|
||||
ResultSet rs = doExecuteQuery(stmt, "SELECT x,y,zoom,Format FROM Tiles WHERE MapID=" + mapkey + ";");
|
||||
while (rs.next()) {
|
||||
StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var);
|
||||
final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
|
||||
if(cb != null)
|
||||
cb.tileFound(st, encoding);
|
||||
if(cbBase != null && st.zoom == 0)
|
||||
cbBase.tileFound(st, encoding);
|
||||
st.cleanup();
|
||||
boolean done = false;
|
||||
int offset = 0;
|
||||
int limit = 100;
|
||||
while (!done) {
|
||||
c = getConnection(); // Do inside loop - single threaded sqlite will have issues otherwise....
|
||||
// Query tiles for given mapkey
|
||||
Statement stmt = c.createStatement();
|
||||
ResultSet rs = doExecuteQuery(stmt, String.format("SELECT x,y,zoom,Format FROM Tiles WHERE MapID=%d LIMIT %d OFFSET %d;", mapkey, limit, offset));
|
||||
int cnt = 0;
|
||||
while (rs.next()) {
|
||||
StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var);
|
||||
final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
|
||||
if(cb != null)
|
||||
cb.tileFound(st, encoding);
|
||||
if(cbBase != null && st.zoom == 0)
|
||||
cbBase.tileFound(st, encoding);
|
||||
st.cleanup();
|
||||
cnt++;
|
||||
}
|
||||
rs.close();
|
||||
stmt.close();
|
||||
if (cnt < limit) done = true;
|
||||
offset += cnt;
|
||||
releaseConnection(c, err);
|
||||
c = null;
|
||||
}
|
||||
if(cbEnd != null)
|
||||
cbEnd.searchEnded();
|
||||
rs.close();
|
||||
stmt.close();
|
||||
} catch (SQLException x) {
|
||||
logSQLException("Tile enum error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -651,6 +729,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Tile purge error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -693,6 +773,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -727,6 +809,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -753,6 +837,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Face exists error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -804,6 +890,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (rs != null) { try { rs.close(); } catch (SQLException sx) {} }
|
||||
if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} }
|
||||
|
@ -838,6 +926,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -885,6 +975,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker file write error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
if (rs != null) { try { rs.close(); } catch (SQLException sx) {} }
|
||||
if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} }
|
||||
|
@ -913,6 +1005,8 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
} catch (SQLException x) {
|
||||
logSQLException("Marker file read error", x);
|
||||
err = true;
|
||||
} catch (StorageShutdownException x) {
|
||||
err = true;
|
||||
} finally {
|
||||
releaseConnection(c, err);
|
||||
}
|
||||
|
@ -985,4 +1079,11 @@ public class SQLiteMapStorage extends MapStorage {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void logSQLException(String opmsg, SQLException x) {
|
||||
// Ignore interrupted
|
||||
if (x.getMessage().equals("Interrupted")) return;
|
||||
|
||||
super.logSQLException(opmsg, x);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ public class DataBitsPacked {
|
|||
private final long[] values;
|
||||
private final int bitsperrec;
|
||||
private final long valuemask;
|
||||
private final int length;
|
||||
public final int length;
|
||||
|
||||
public static int calcLongCount(int i, int j) {
|
||||
if (j == 0) {
|
||||
|
|
|
@ -107,68 +107,126 @@ public class ImageIOManager {
|
|||
}
|
||||
|
||||
public static BufferOutputStream imageIOEncode(BufferedImage img, ImageFormat fmt) {
|
||||
BufferOutputStream bos = new BufferOutputStream();
|
||||
|
||||
if(isRequiredJDKVersion(17,-1,-1)){
|
||||
return imageIOEncodeUnsafe(img, fmt); //we can skip Thread safety for more performance
|
||||
}
|
||||
synchronized(imageioLock) {
|
||||
try {
|
||||
ImageIO.setUseCache(false); /* Don't use file cache - too small to be worth it */
|
||||
|
||||
fmt = validateFormat(fmt);
|
||||
|
||||
if(fmt.getEncoding() == ImageEncoding.JPG) {
|
||||
WritableRaster raster = img.getRaster();
|
||||
WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(),
|
||||
img.getHeight(), 0, 0, new int[] {0, 1, 2});
|
||||
DirectColorModel cm = (DirectColorModel)img.getColorModel();
|
||||
DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
|
||||
cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());
|
||||
// now create the new buffer that is used ot write the image:
|
||||
BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
|
||||
return imageIOEncodeUnsafe(img, fmt);
|
||||
}
|
||||
}
|
||||
private static BufferOutputStream imageIOEncodeUnsafe(BufferedImage img, ImageFormat fmt) {
|
||||
BufferOutputStream bos = new BufferOutputStream();
|
||||
try {
|
||||
ImageIO.setUseCache(false); /* Don't use file cache - too small to be worth it */
|
||||
|
||||
// Find a jpeg writer
|
||||
ImageWriter writer = null;
|
||||
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpg");
|
||||
if (iter.hasNext()) {
|
||||
writer = iter.next();
|
||||
}
|
||||
if(writer == null) {
|
||||
Log.severe("No JPEG ENCODER - Java VM does not support JPEG encoding");
|
||||
return null;
|
||||
}
|
||||
ImageWriteParam iwp = writer.getDefaultWriteParam();
|
||||
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
iwp.setCompressionQuality(fmt.getQuality());
|
||||
fmt = validateFormat(fmt);
|
||||
|
||||
ImageOutputStream ios;
|
||||
ios = ImageIO.createImageOutputStream(bos);
|
||||
writer.setOutput(ios);
|
||||
if(fmt.getEncoding() == ImageEncoding.JPG) {
|
||||
WritableRaster raster = img.getRaster();
|
||||
WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(),
|
||||
img.getHeight(), 0, 0, new int[] {0, 1, 2});
|
||||
DirectColorModel cm = (DirectColorModel)img.getColorModel();
|
||||
DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
|
||||
cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());
|
||||
// now create the new buffer that is used ot write the image:
|
||||
BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
|
||||
|
||||
writer.write(null, new IIOImage(rgbBuffer, null, null), iwp);
|
||||
writer.dispose();
|
||||
|
||||
rgbBuffer.flush();
|
||||
// Find a jpeg writer
|
||||
ImageWriter writer = null;
|
||||
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpg");
|
||||
if (iter.hasNext()) {
|
||||
writer = iter.next();
|
||||
}
|
||||
else if (fmt.getEncoding() == ImageEncoding.WEBP) {
|
||||
doWEBPEncode(img, fmt, bos);
|
||||
if(writer == null) {
|
||||
Log.severe("No JPEG ENCODER - Java VM does not support JPEG encoding");
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
ImageIO.write(img, fmt.getFileExt(), bos); /* Write to byte array stream - prevent bogus I/O errors */
|
||||
}
|
||||
} catch (IOException iox) {
|
||||
Log.info("Error encoding image - " + iox.getMessage());
|
||||
return null;
|
||||
ImageWriteParam iwp = writer.getDefaultWriteParam();
|
||||
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
iwp.setCompressionQuality(fmt.getQuality());
|
||||
|
||||
ImageOutputStream ios;
|
||||
ios = ImageIO.createImageOutputStream(bos);
|
||||
writer.setOutput(ios);
|
||||
|
||||
writer.write(null, new IIOImage(rgbBuffer, null, null), iwp);
|
||||
writer.dispose();
|
||||
|
||||
rgbBuffer.flush();
|
||||
}
|
||||
else if (fmt.getEncoding() == ImageEncoding.WEBP) {
|
||||
doWEBPEncode(img, fmt, bos);
|
||||
}
|
||||
else {
|
||||
ImageIO.write(img, fmt.getFileExt(), bos); /* Write to byte array stream - prevent bogus I/O errors */
|
||||
}
|
||||
} catch (IOException iox) {
|
||||
Log.info("Error encoding image - " + iox.getMessage());
|
||||
return null;
|
||||
}
|
||||
return bos;
|
||||
}
|
||||
|
||||
|
||||
public static BufferedImage imageIODecode(MapStorageTile.TileRead tr) throws IOException {
|
||||
if(isRequiredJDKVersion(17,-1,-1)){
|
||||
return imageIODecodeUnsafe(tr); //we can skip Thread safety for more performance
|
||||
}
|
||||
synchronized(imageioLock) {
|
||||
ImageIO.setUseCache(false); /* Don't use file cache - too small to be worth it */
|
||||
if (tr.format == ImageEncoding.WEBP) {
|
||||
return doWEBPDecode(tr.image);
|
||||
}
|
||||
return ImageIO.read(tr.image);
|
||||
return imageIODecodeUnsafe(tr);
|
||||
}
|
||||
}
|
||||
|
||||
private static BufferedImage imageIODecodeUnsafe(MapStorageTile.TileRead tr) throws IOException {
|
||||
ImageIO.setUseCache(false); /* Don't use file cache - too small to be worth it */
|
||||
if (tr.format == ImageEncoding.WEBP) {
|
||||
return doWEBPDecode(tr.image);
|
||||
}
|
||||
return ImageIO.read(tr.image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current JDK is running at least a specific version
|
||||
* targetMinor and targetBuild can be set to -1, if the java.version only provides a Major release this will then only check for the major release
|
||||
* @param targetMajor the required minimum major version
|
||||
* @param targetMinor the required minimum minor version
|
||||
* @param targetBuild the required minimum build version
|
||||
* @return true if the current JDK version is the required minimum version
|
||||
*/
|
||||
private static boolean isRequiredJDKVersion(int targetMajor, int targetMinor, int targetBuild){
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
String[] versionParts = javaVersion.split("\\.");
|
||||
if(versionParts.length < 3){
|
||||
if(versionParts.length == 1
|
||||
&& targetMinor == -1
|
||||
&& targetBuild == -1
|
||||
&& parseInt(versionParts[0], -1) >= targetMajor){
|
||||
return true;//we only have a major version and thats ok
|
||||
}
|
||||
return false; //can not evaluate
|
||||
}
|
||||
int major = parseInt(versionParts[0], -1);
|
||||
int minor = parseInt(versionParts[1], -1);
|
||||
int build = parseInt(versionParts[2], -1);
|
||||
if(major != -1 && major >= targetMajor &&
|
||||
minor != -1 && minor >= targetMinor &&
|
||||
build != -1 && build >= targetBuild
|
||||
){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string to int, with a dynamic fallback value if not parsable
|
||||
* @param input the String to parse
|
||||
* @param fallback the Fallback value to use
|
||||
* @return the parsed integer or the fallback value if unparsable
|
||||
*/
|
||||
private static int parseInt(String input, int fallback){
|
||||
int output = fallback;
|
||||
try{
|
||||
output = Integer.parseInt(input);
|
||||
} catch (NumberFormatException e) {}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package org.dynmap.utils;
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* Matches a request based on IP Address or subnet mask matching against the remote
|
||||
* address.
|
||||
* <p>
|
||||
* Both IPv6 and IPv4 addresses are supported, but a matcher which is configured with an
|
||||
* IPv4 address will never match a request which returns an IPv6 address, and vice-versa.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0.2
|
||||
*
|
||||
* Slightly modified by omidzk to have zero dependency to any frameworks other than the JRE.
|
||||
*/
|
||||
public final class IpAddressMatcher {
|
||||
private final int nMaskBits;
|
||||
private final InetAddress requiredAddress;
|
||||
|
||||
/**
|
||||
* Takes a specific IP address or a range specified using the IP/Netmask (e.g.
|
||||
* 192.168.1.0/24 or 202.24.0.0/14).
|
||||
*
|
||||
* @param ipAddress the address or range of addresses from which the request must
|
||||
* come.
|
||||
*/
|
||||
public IpAddressMatcher(String ipAddress) {
|
||||
|
||||
if (ipAddress.indexOf('/') > 0) {
|
||||
String[] addressAndMask = ipAddress.split("/");
|
||||
ipAddress = addressAndMask[0];
|
||||
nMaskBits = Integer.parseInt(addressAndMask[1]);
|
||||
}
|
||||
else {
|
||||
nMaskBits = -1;
|
||||
}
|
||||
requiredAddress = parseAddress(ipAddress);
|
||||
assert (requiredAddress.getAddress().length * 8 >= nMaskBits) :
|
||||
String.format("IP address %s is too short for bitmask of length %d",
|
||||
ipAddress, nMaskBits);
|
||||
}
|
||||
|
||||
public boolean matches(String address) {
|
||||
InetAddress remoteAddress = parseAddress(address);
|
||||
|
||||
if (!requiredAddress.getClass().equals(remoteAddress.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nMaskBits < 0) {
|
||||
return remoteAddress.equals(requiredAddress);
|
||||
}
|
||||
|
||||
byte[] remAddr = remoteAddress.getAddress();
|
||||
byte[] reqAddr = requiredAddress.getAddress();
|
||||
|
||||
int nMaskFullBytes = nMaskBits / 8;
|
||||
byte finalByte = (byte) (0xFF00 >> (nMaskBits & 0x07));
|
||||
|
||||
// System.out.println("Mask is " + new sun.misc.HexDumpEncoder().encode(mask));
|
||||
|
||||
for (int i = 0; i < nMaskFullBytes; i++) {
|
||||
if (remAddr[i] != reqAddr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (finalByte != 0) {
|
||||
return (remAddr[nMaskFullBytes] & finalByte) == (reqAddr[nMaskFullBytes] & finalByte);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private InetAddress parseAddress(String address) {
|
||||
try {
|
||||
return InetAddress.getByName(address);
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
throw new IllegalArgumentException("Failed to parse address" + address, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -106,10 +106,18 @@ public interface MapIterator extends MapDataContext {
|
|||
*/
|
||||
BlockStep getLastStep();
|
||||
/**
|
||||
* Get world height
|
||||
* Get world height (yMax+1)
|
||||
* @return height
|
||||
*/
|
||||
int getWorldHeight();
|
||||
/**
|
||||
* Get world bottom (yMin)
|
||||
*/
|
||||
int getWorldYMin();
|
||||
/**
|
||||
* Get world sealevel
|
||||
*/
|
||||
int getWorldSeaLevel();
|
||||
/**
|
||||
* Get block key for current position (unique ID for block within cache being iterated)
|
||||
* @return block key
|
||||
|
|
|
@ -29,6 +29,7 @@ public class PatchDefinition implements RenderPatch {
|
|||
public SideVisible sidevis; /* Which side is visible */
|
||||
public int textureindex;
|
||||
public BlockStep step; /* Best approximation of orientation of surface, from top (positive determinent) */
|
||||
public boolean shade; // If false, patch is not shaded
|
||||
private int hc;
|
||||
/* Offset vector of middle of block */
|
||||
private static final Vector3D offsetCenter = new Vector3D(0.5,0.5,0.5);
|
||||
|
@ -45,6 +46,7 @@ public class PatchDefinition implements RenderPatch {
|
|||
v = new Vector3D();
|
||||
sidevis = SideVisible.BOTH;
|
||||
textureindex = 0;
|
||||
shade = true;
|
||||
update();
|
||||
}
|
||||
PatchDefinition(PatchDefinition pd) {
|
||||
|
@ -68,6 +70,7 @@ public class PatchDefinition implements RenderPatch {
|
|||
this.sidevis = pd.sidevis;
|
||||
this.textureindex = pd.textureindex;
|
||||
this.step = pd.step;
|
||||
this.shade = pd.shade;
|
||||
this.hc = pd.hc;
|
||||
}
|
||||
/**
|
||||
|
@ -110,6 +113,7 @@ public class PatchDefinition implements RenderPatch {
|
|||
vmaxatumax = orig.vmaxatumax;
|
||||
vminatumax = orig.vminatumax;
|
||||
sidevis = orig.sidevis;
|
||||
shade = orig.shade;
|
||||
this.textureindex = (textureindex < 0) ? orig.textureindex : textureindex;
|
||||
u = new Vector3D();
|
||||
v = new Vector3D();
|
||||
|
@ -140,7 +144,7 @@ public class PatchDefinition implements RenderPatch {
|
|||
public void update(double x0, double y0, double z0, double xu,
|
||||
double yu, double zu, double xv, double yv, double zv, double umin,
|
||||
double umax, double vmin, double vmax, SideVisible sidevis,
|
||||
int textureids, double vminatumax, double vmaxatumax) {
|
||||
int textureids, double vminatumax, double vmaxatumax, boolean shade) {
|
||||
this.x0 = x0;
|
||||
this.y0 = y0;
|
||||
this.z0 = z0;
|
||||
|
@ -158,6 +162,7 @@ public class PatchDefinition implements RenderPatch {
|
|||
this.vminatumax = vminatumax;
|
||||
this.sidevis = sidevis;
|
||||
this.textureindex = textureids;
|
||||
this.shade = shade;
|
||||
update();
|
||||
}
|
||||
public void update() {
|
||||
|
@ -211,70 +216,38 @@ public class PatchDefinition implements RenderPatch {
|
|||
}
|
||||
}
|
||||
}
|
||||
private boolean outOfRange(double v) {
|
||||
return (v < -1.0) || (v > 2.0);
|
||||
}
|
||||
public boolean validate() {
|
||||
boolean good = true;
|
||||
if((x0 < -1.0) || (x0 > 2.0)) {
|
||||
Log.severe("Invalid x0=" + x0);
|
||||
good = false;
|
||||
// Compute visible corners to see if we're inside cube
|
||||
double xx0 = x0 + (xu - x0) * umin + (xv - x0) * vmin;
|
||||
double xx1 = x0 + (xu - x0) * vmin + (xv - x0) * vmax;
|
||||
double xx2 = x0 + (xu - x0) * umax + (xv - x0) * vmin;
|
||||
double xx3 = x0 + (xu - x0) * vmax + (xv - x0) * vmax;;
|
||||
if (outOfRange(xx0) || outOfRange(xx1) || outOfRange(xx2) || outOfRange(xx3)) {
|
||||
Log.verboseinfo(String.format("Invalid visible range xu=[%f:%f], xv=[%f:%f]", xx0, xx2, xx1, xx3));
|
||||
good = false;
|
||||
}
|
||||
if((y0 < -1.0) || (y0 > 2.0)) {
|
||||
Log.severe("Invalid y0=" + y0);
|
||||
good = false;
|
||||
double yy0 = y0 + (yu - y0) * umin + (yv - y0) * vmin;
|
||||
double yy1 = y0 + (yu - y0) * vmin + (yv - y0) * vmax;
|
||||
double yy2 = y0 + (yu - y0) * umax + (yv - y0) * vmin;
|
||||
double yy3 = y0 + (yu - y0) * vmax + (yv - y0) * vmax;;
|
||||
if (outOfRange(yy0) || outOfRange(yy1) || outOfRange(yy2) || outOfRange(yy3)) {
|
||||
Log.verboseinfo(String.format("Invalid visible range yu=[%f:%f], yv=[%f:%f]", yy0, yy2, yy1, yy3));
|
||||
good = false;
|
||||
}
|
||||
if((z0 < -1.0) || (z0 > 2.0)) {
|
||||
Log.severe("Invalid z0=" + z0);
|
||||
good = false;
|
||||
}
|
||||
if((xu < -1.0) || (xu > 2.0)) {
|
||||
Log.severe("Invalid xu=" + xu);
|
||||
good = false;
|
||||
}
|
||||
if((yu < -1.0) || (yu > 2.0)) {
|
||||
Log.severe("Invalid yu=" + yu);
|
||||
good = false;
|
||||
}
|
||||
if((zu < -1.0) || (zu > 2.0)) {
|
||||
Log.severe("Invalid zu=" + zu);
|
||||
good = false;
|
||||
}
|
||||
if((xv < -1.0) || (xv > 2.0)) {
|
||||
Log.severe("Invalid xv=" + xv);
|
||||
good = false;
|
||||
}
|
||||
if((yv < -1.0) || (yv > 2.0)) {
|
||||
Log.severe("Invalid yv=" + yv);
|
||||
good = false;
|
||||
}
|
||||
if((zv < -1.0) || (zv > 2.0)) {
|
||||
Log.severe("Invalid zv=" + zv);
|
||||
good = false;
|
||||
}
|
||||
if((umin < 0.0) || (umin > umax)) {
|
||||
Log.severe("Invalid umin=" + umin);
|
||||
good = false;
|
||||
}
|
||||
if((vmin < 0.0) || (vmin > vmax)) {
|
||||
Log.severe("Invalid vmin=" + vmin);
|
||||
good = false;
|
||||
}
|
||||
if(umax > 1.0) {
|
||||
Log.severe("Invalid umax=" + umax);
|
||||
good = false;
|
||||
}
|
||||
if(vmax > 1.0) {
|
||||
Log.severe("Invalid vmax=" + vmax);
|
||||
good = false;
|
||||
}
|
||||
if ((vminatumax < 0.0) || (vminatumax > vmaxatumax)) {
|
||||
Log.severe("Invalid vminatumax=" + vminatumax);
|
||||
good = false;
|
||||
}
|
||||
if(vmaxatumax > 1.0) {
|
||||
Log.severe("Invalid vmaxatumax=" + vmaxatumax);
|
||||
good = false;
|
||||
double zz0 = z0 + (zu - z0) * umin + (zv - z0) * vmin;
|
||||
double zz1 = z0 + (zu - z0) * vmin + (zv - z0) * vmax;
|
||||
double zz2 = z0 + (zu - z0) * umax + (zv - z0) * vmin;
|
||||
double zz3 = z0 + (zu - z0) * vmax + (zv - z0) * vmax;
|
||||
if (outOfRange(zz0) || outOfRange(zz1) || outOfRange(zz2) || outOfRange(zz3)) {
|
||||
Log.verboseinfo(String.format("Invalid visible range zu=[%f:%f], zv=[%f:%f]", zz0, zz2, zz1, zz3));
|
||||
good = false;
|
||||
}
|
||||
if (!good) {
|
||||
Log.warning("Patch not valid: " + toString());
|
||||
Log.verboseinfo("Bad patch: " + this);
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
@ -291,7 +264,8 @@ public class PatchDefinition implements RenderPatch {
|
|||
(umin == p.umin) && (umax == p.umax) &&
|
||||
(vmin == p.vmin) && (vmax == p.vmax) &&
|
||||
(vmaxatumax == p.vmaxatumax) &&
|
||||
(vminatumax == p.vminatumax) && (sidevis == p.sidevis)) {
|
||||
(vminatumax == p.vminatumax) && (sidevis == p.sidevis) &&
|
||||
(shade == p.shade)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -307,8 +281,8 @@ public class PatchDefinition implements RenderPatch {
|
|||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("xyz0=%f/%f/%f,xyzU=%f/%f/%f,xyzV=%f/%f/%f,minU=%f,maxU=%f,vMin=%f/%f,vmax=%f/%f,side=%s,txtidx=%d",
|
||||
x0, y0, z0, xu, yu, zu, xv, yv, zv, umin, umax, vmin, vminatumax, vmax, vmaxatumax, sidevis, textureindex);
|
||||
return String.format("xyz0=%f/%f/%f,xyzU=%f/%f/%f,xyzV=%f/%f/%f,minU=%f,maxU=%f,vMin=%f/%f,vmax=%f/%f,side=%s,txtidx=%d,shade=%b",
|
||||
x0, y0, z0, xu, yu, zu, xv, yv, zv, umin, umax, vmin, vminatumax, vmax, vmaxatumax, sidevis, textureindex, shade);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -324,8 +298,9 @@ public class PatchDefinition implements RenderPatch {
|
|||
// @param face - which face (determines use of xyz-min vs xyz-max
|
||||
// @param uv - bounds on UV (umin, vmin, umax, vmax): if undefined, default based on face range (minecraft UV is relative to top left corner of texture)
|
||||
// @param rot - texture rotation (default 0 - DEG0, DEG90, DEG180, DEG270)
|
||||
// @param shade - if false, no shadows on patch
|
||||
// @param textureid - texture ID
|
||||
public void updateModelFace(double[] from, double[] to, BlockSide face, double[] uv, ModelBlockModel.SideRotation rot, int textureid) {
|
||||
public void updateModelFace(double[] from, double[] to, BlockSide face, double[] uv, ModelBlockModel.SideRotation rot, boolean shade, int textureid) {
|
||||
if (rot == null) rot = ModelBlockModel.SideRotation.DEG0;
|
||||
// Compute corners of the face
|
||||
Vector3D lowleft;
|
||||
|
@ -337,9 +312,12 @@ public class PatchDefinition implements RenderPatch {
|
|||
boolean flipU = false, flipV = false;
|
||||
if (uv != null) { // MC V is top down, so flip
|
||||
patchuv = new double[] { uv[0] / 16.0, 1 - uv[3] / 16.0, uv[2] / 16.0, 1 - uv[1] / 16.0 };
|
||||
if (patchuv[0] > patchuv[2]) { flipU = true; double save = patchuv[0]; patchuv[0] = patchuv[2]; patchuv[2] = save; }
|
||||
if (patchuv[1] > patchuv[3]) { flipV = true; double save = patchuv[1]; patchuv[1] = patchuv[3]; patchuv[3] = save; }
|
||||
// if (patchuv[0] > patchuv[2]) { flipU = true; double save = patchuv[0]; patchuv[0] = patchuv[2]; patchuv[2] = save; }
|
||||
// if (patchuv[1] > patchuv[3]) { flipV = true; double save = patchuv[1]; patchuv[1] = patchuv[3]; patchuv[3] = save; }
|
||||
if (patchuv[0] > patchuv[2]) { flipU = true; patchuv[0] = 1.0 - patchuv[0]; patchuv[2] = 1.0 - patchuv[2]; }
|
||||
if (patchuv[1] > patchuv[3]) { flipV = true; patchuv[1] = 1.0 - patchuv[1]; patchuv[3] = 1.0 - patchuv[3]; }
|
||||
}
|
||||
|
||||
switch (face) {
|
||||
case BOTTOM:
|
||||
case FACE_0:
|
||||
|
@ -448,7 +426,6 @@ public class PatchDefinition implements RenderPatch {
|
|||
upleft = upright;
|
||||
upright = save;
|
||||
}
|
||||
//System.out.println(String.format("ll=%s, lr=%s, ul=%s, ur=%s", lowleft, lowright, upleft, upright));
|
||||
// Compute texture origin, based on corners and patchuv
|
||||
Vector3D txtorig = new Vector3D();
|
||||
Vector3D txtU = new Vector3D();
|
||||
|
@ -460,12 +437,12 @@ public class PatchDefinition implements RenderPatch {
|
|||
double du = patchuv[2] - patchuv[0];
|
||||
txtU.set(lowright).subtract(lowleft); // vector along U
|
||||
double uScale = txtU.length() / du;
|
||||
txtU.scale(uScale / du); // Compute full U vect
|
||||
txtU.scale(uScale / txtU.length()); // Compute full U vect
|
||||
// Compute V axis
|
||||
double dv = patchuv[3] - patchuv[1];
|
||||
txtV.set(upleft).subtract(lowleft); // vector along V
|
||||
double vScale = txtV.length() / dv;
|
||||
txtV.scale(vScale / dv); // Compute full V vect
|
||||
txtV.scale(vScale / txtV.length()); // Compute full V vect
|
||||
// Compute texture origin
|
||||
txtorig.set(txtU).scale(-patchuv[0]).add(lowleft);
|
||||
wrk.set(txtV).scale(-patchuv[1]);
|
||||
|
@ -474,9 +451,8 @@ public class PatchDefinition implements RenderPatch {
|
|||
txtU.add(txtorig); // And add it for full U
|
||||
txtV.add(txtorig); // And add it to compute full V
|
||||
}
|
||||
// System.out.println(String.format("txtO=%s, txtU=%s, txtV=%s, uv=%f/%f/%f/%f", txtorig, txtU, txtV, patchuv[0], patchuv[1], patchuv[2],
|
||||
// patchuv[3]));
|
||||
update(txtorig.x, txtorig.y, txtorig.z, txtU.x, txtU.y, txtU.z, txtV.x, txtV.y, txtV.z,
|
||||
patchuv[0], patchuv[2], patchuv[1], patchuv[3], flipU ? SideVisible.TOPFLIP : (flipV ? SideVisible.TOPFLIPV : SideVisible.TOP), textureid, patchuv[1], patchuv[3]);
|
||||
patchuv[0], patchuv[2], patchuv[1], patchuv[3], flipU ? (flipV ? SideVisible.TOPFLIPHV : SideVisible.TOPFLIP) : (flipV ? SideVisible.TOPFLIPV : SideVisible.TOP), textureid,
|
||||
patchuv[1], patchuv[3], shade);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@ import org.dynmap.modsupport.BlockSide;
|
|||
import org.dynmap.modsupport.ModelBlockModel;
|
||||
import org.dynmap.renderer.RenderPatch;
|
||||
import org.dynmap.renderer.RenderPatchFactory;
|
||||
import org.dynmap.renderer.RenderPatchFactory.SideVisible;
|
||||
import org.dynmap.Log;
|
||||
|
||||
public class PatchDefinitionFactory implements RenderPatchFactory {
|
||||
private HashMap<PatchDefinition,PatchDefinition> patches = new HashMap<PatchDefinition,PatchDefinition>();
|
||||
|
@ -30,30 +28,30 @@ public class PatchDefinitionFactory implements RenderPatchFactory {
|
|||
double yu, double zu, double xv, double yv, double zv, double umin,
|
||||
double umax, double vmin, double vmax, SideVisible sidevis,
|
||||
int textureids) {
|
||||
return getPatch(x0, y0, z0, xu, yu, zu,xv, yv, zv, umin, umax, vmin, vmax, sidevis, textureids, vmin, vmax);
|
||||
return getPatch(x0, y0, z0, xu, yu, zu,xv, yv, zv, umin, umax, vmin, vmax, sidevis, textureids, vmin, vmax, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderPatch getPatch(double x0, double y0, double z0, double xu,
|
||||
double yu, double zu, double xv, double yv, double zv,
|
||||
double uplusvmax, SideVisible sidevis, int textureids) {
|
||||
return getPatch(x0, y0, z0, xu, yu, zu,xv, yv, zv, 0.0, uplusvmax, 0.0, uplusvmax, sidevis, textureids, 0.0, 0.0);
|
||||
return getPatch(x0, y0, z0, xu, yu, zu,xv, yv, zv, 0.0, uplusvmax, 0.0, uplusvmax, sidevis, textureids, 0.0, 0.0, true);
|
||||
}
|
||||
@Override
|
||||
public PatchDefinition getPatch(double x0, double y0, double z0, double xu,
|
||||
double yu, double zu, double xv, double yv, double zv, double umin,
|
||||
double umax, double vmin, double vminatumax, double vmax, double vmaxatumax, SideVisible sidevis,
|
||||
int textureids) {
|
||||
return getPatch(x0, y0, z0, xu, yu, zu,xv, yv, zv, umin, umax, vmin, vmax, sidevis, textureids, vminatumax, vmaxatumax);
|
||||
return getPatch(x0, y0, z0, xu, yu, zu,xv, yv, zv, umin, umax, vmin, vmax, sidevis, textureids, vminatumax, vmaxatumax, true);
|
||||
}
|
||||
|
||||
public PatchDefinition getPatch(double x0, double y0, double z0, double xu,
|
||||
double yu, double zu, double xv, double yv, double zv, double umin,
|
||||
double umax, double vmin, double vmax, SideVisible sidevis,
|
||||
int textureids, double vminatumax, double vmaxatumax) {
|
||||
int textureids, double vminatumax, double vmaxatumax, boolean shade) {
|
||||
synchronized(lock) {
|
||||
lookup.update(x0, y0, z0, xu, yu, zu, xv, yv, zv, umin,
|
||||
umax, vmin, vmax, sidevis, textureids, vminatumax, vmaxatumax);
|
||||
umax, vmin, vmax, sidevis, textureids, vminatumax, vmaxatumax, shade);
|
||||
if(lookup.validate() == false)
|
||||
return null;
|
||||
PatchDefinition pd2 = patches.get(lookup); /* See if in cache already */
|
||||
|
@ -66,10 +64,10 @@ public class PatchDefinitionFactory implements RenderPatchFactory {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public PatchDefinition getModelFace(double[] from, double[] to, BlockSide face, double[] uv, ModelBlockModel.SideRotation rot, int textureid) {
|
||||
|
||||
public PatchDefinition getModelFace(double[] from, double[] to, BlockSide face, double[] uv, ModelBlockModel.SideRotation rot, boolean shade, int textureid) {
|
||||
synchronized(lock) {
|
||||
lookup.updateModelFace(from, to, face, uv, rot, textureid);
|
||||
lookup.updateModelFace(from, to, face, uv, rot, shade, textureid);
|
||||
if(lookup.validate() == false)
|
||||
return null;
|
||||
PatchDefinition pd2 = patches.get(lookup); /* See if in cache already */
|
||||
|
@ -198,24 +196,26 @@ public class PatchDefinitionFactory implements RenderPatchFactory {
|
|||
return TexturePack.getTextureMapLength(id);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
PatchDefinitionFactory fact = new PatchDefinitionFactory();
|
||||
PatchDefinition pd;
|
||||
BlockSide[] faces = { BlockSide.NORTH, BlockSide.EAST, BlockSide.SOUTH, BlockSide.WEST, BlockSide.TOP, BlockSide.BOTTOM };
|
||||
// campfire log:box=1/0/0:5/4/16:n/0/0/4/4/8:e/0/0/1/16/5:s/0/0/4/4/8:w/0/16/0/0/4:u90/0/0/0/16/4:d90/0/0/0/16/4
|
||||
double[][] uvs = { { 0, 4, 4, 8 }, { 0, 1, 16, 5 }, { 0, 4, 4, 8 }, { 16, 0, 0, 4 }, { 0, 0, 16, 4 }, { 0, 0, 16, 4 } };
|
||||
ModelBlockModel.SideRotation[] rots = { ModelBlockModel.SideRotation.DEG0, ModelBlockModel.SideRotation.DEG0, ModelBlockModel.SideRotation.DEG0,
|
||||
ModelBlockModel.SideRotation.DEG0, ModelBlockModel.SideRotation.DEG90, ModelBlockModel.SideRotation.DEG90 };
|
||||
double[] from = { 1, 0, 0 };
|
||||
double[] to = { 5, 4, 16 };
|
||||
|
||||
// Do normal faces, default limits
|
||||
pd = new PatchDefinition();
|
||||
for (int i = 0; i < faces.length; i++) {
|
||||
pd.updateModelFace(from, to, faces[i], uvs[i], rots[i], 0);
|
||||
System.out.println("Log " + faces[i] + ": " + pd);
|
||||
}
|
||||
|
||||
// public static void main(String[] args) {
|
||||
// PatchDefinition pd;
|
||||
//
|
||||
// // box=0.000000/3.000000/9.000000:2.000000/6.000000/13.000000:
|
||||
// // w/0/13.000000/7.000000/15.000000/10.000000:d/0/0.000000/9.000000/2.000000/13.000000:e/0/13.000000/7.000000/15.000000/10.000000:u/0/0.000000/9.000000/2.000000/13.000000:R/0/180/0
|
||||
// BlockSide[] faces = { BlockSide.WEST, BlockSide.BOTTOM, BlockSide.EAST, BlockSide.TOP };
|
||||
// // campfire log:box=1/0/0:5/4/16:n/0/0/4/4/8:e/0/0/1/16/5:s/0/0/4/4/8:w/0/16/0/0/4:u90/0/0/0/16/4:d90/0/0/0/16/4
|
||||
// double[][] uvs = { { 13, 7, 15, 10 }, { 0, 9, 2, 13 }, { 13, 7, 15, 10 }, { 0, 9, 2, 13 } };
|
||||
// ModelBlockModel.SideRotation[] rots = { ModelBlockModel.SideRotation.DEG0, ModelBlockModel.SideRotation.DEG0, ModelBlockModel.SideRotation.DEG0,
|
||||
// ModelBlockModel.SideRotation.DEG0 };
|
||||
// double[] from = { 0, 3, 9 };
|
||||
// double[] to = { 2, 6, 13 };
|
||||
//
|
||||
// // Do normal faces, default limits
|
||||
// pd = new PatchDefinition();
|
||||
// for (int i = 0; i < faces.length; i++) {
|
||||
// pd.updateModelFace(from, to, faces[i], uvs[i], rots[i], true, 0);
|
||||
// System.out.println("Log " + faces[i] + ": " + pd);
|
||||
// }
|
||||
//
|
||||
// // Do normal faces, default limits
|
||||
// pd = new PatchDefinition();
|
||||
// for (BlockSide face : faces) {
|
||||
|
@ -234,6 +234,6 @@ public class PatchDefinitionFactory implements RenderPatchFactory {
|
|||
// pd.updateModelFace(from, toquarter, face, new double[] { 4, 4, 12, 12 }, 0);
|
||||
// System.out.println("Full cube, middle half of texture " + face + ": " + pd);
|
||||
// }
|
||||
|
||||
}
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -25,7 +25,11 @@ public class RoundVisibilityLimit implements VisibilityLimit {
|
|||
else
|
||||
chunk_corner_z = chunk_z * 16 + 15;
|
||||
|
||||
return (chunk_corner_x - x_center) * (chunk_corner_x - x_center) + (chunk_corner_z - z_center) * (chunk_corner_z - z_center) < radius * radius;
|
||||
// By gmfamily - Use long representation of the distance between tested chunk and center of tested limit
|
||||
// to avoid int overflow while computing the distance compared to limit radius using square delta value
|
||||
long chunk_delta_x = chunk_corner_x - x_center;
|
||||
long chunk_delta_z = chunk_corner_z - z_center;
|
||||
return chunk_delta_x * chunk_delta_x + chunk_delta_z * chunk_delta_z < (long) radius * radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,18 +11,27 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class HandlerRouter extends AbstractHandler {
|
||||
|
||||
PathMap pathMap = new PathMap();
|
||||
PathMap<HandlerOrServlet> pathMap = new PathMap<HandlerOrServlet>();
|
||||
|
||||
private static class HandlerOrServlet {
|
||||
Servlet servlet;
|
||||
Handler handler;
|
||||
HandlerOrServlet(Servlet s) { servlet = s; handler = null; }
|
||||
HandlerOrServlet(Handler h) { servlet = null; handler = h; }
|
||||
};
|
||||
|
||||
public HandlerRouter() {
|
||||
}
|
||||
|
||||
public void addHandler(String path, Handler handler) {
|
||||
pathMap.put(path, handler);
|
||||
pathMap.put(path, new HandlerOrServlet(handler));
|
||||
}
|
||||
|
||||
public void addServlet(String path, Servlet servlet) {
|
||||
pathMap.put(path, servlet);
|
||||
pathMap.put(path, new HandlerOrServlet(servlet));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
@ -32,7 +41,7 @@ public class HandlerRouter extends AbstractHandler {
|
|||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String pathInfo = request.getPathInfo();
|
||||
PathMap.MappedEntry e = pathMap.getMatch(pathInfo);
|
||||
PathMap.MappedEntry<HandlerOrServlet> e = pathMap.getMatch(pathInfo);
|
||||
String mappedPath = e.getMapped();
|
||||
|
||||
String childPathInfo = pathInfo;
|
||||
|
@ -45,13 +54,12 @@ public class HandlerRouter extends AbstractHandler {
|
|||
org.eclipse.jetty.server.Request r = (org.eclipse.jetty.server.Request)request;
|
||||
r.setPathInfo(childPathInfo);
|
||||
|
||||
Object o = e.getValue();
|
||||
if (o instanceof Handler) {
|
||||
Handler h = (Handler)o;
|
||||
h.handle(target, baseRequest, request, response);
|
||||
} else if (o instanceof Servlet) {
|
||||
Servlet s = (Servlet)o;
|
||||
s.service(request, response);
|
||||
HandlerOrServlet o = e.getValue();
|
||||
if (o.handler != null) {
|
||||
o.handler.handle(target, baseRequest, request, response);
|
||||
}
|
||||
else if (o.servlet != null) {
|
||||
o.servlet.service(request, response);
|
||||
}
|
||||
|
||||
r.setPathInfo(pathInfo);
|
||||
|
|
|
@ -411,7 +411,7 @@
|
|||
|
||||
.dynmap .sublist .item > a {
|
||||
display: block;
|
||||
|
||||
|
||||
text-indent: -99999px;
|
||||
outline: none;
|
||||
}
|
||||
|
@ -806,10 +806,10 @@
|
|||
}
|
||||
|
||||
.chatinput {
|
||||
|
||||
position: absolute;
|
||||
width: 608px;
|
||||
height: 16px;
|
||||
|
||||
bottom: 8px;
|
||||
outline: none;
|
||||
color: #fff;
|
||||
background-color: #000000;
|
||||
|
@ -829,6 +829,9 @@
|
|||
}
|
||||
|
||||
.loginbutton {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 4px;
|
||||
color: #000;
|
||||
font-family: sans-serif;
|
||||
font-size: 11px;
|
||||
|
@ -905,15 +908,15 @@
|
|||
|
||||
color: #fff;
|
||||
background: rgba(0,0,0,0.6);
|
||||
padding: 2px;
|
||||
padding: 2px 6px;
|
||||
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerName16x16 {
|
||||
top: -6px;
|
||||
left: 10px;
|
||||
top: -12px;
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
.dynmap .mapMarker .markerName8x8 {
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="images/icons/mstile-150x150.png"/>
|
||||
<TileColor>#ffffff</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,112 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M1205 1970 c3 -5 8 -10 11 -10 2 0 4 5 4 10 0 6 -5 10 -11 10 -5 0
|
||||
-7 -4 -4 -10z"/>
|
||||
<path d="M1170 1940 c0 -4 7 -10 15 -14 8 -3 15 -10 15 -15 0 -6 -7 -8 -15 -5
|
||||
-8 4 -15 1 -15 -5 0 -6 6 -11 13 -11 6 0 12 -12 13 -28 2 -51 15 -103 25 -97
|
||||
5 4 7 11 3 17 -5 8 -8 40 -13 144 -1 13 -41 27 -41 14z"/>
|
||||
<path d="M1250 1880 c-21 -21 -28 -80 -10 -80 6 0 10 9 10 19 0 11 8 26 18 33
|
||||
18 14 26 48 11 48 -5 0 -18 -9 -29 -20z"/>
|
||||
<path d="M701 1785 c-18 -8 -44 -15 -58 -15 -17 0 -24 -5 -22 -17 3 -34 -1
|
||||
-41 -21 -36 -11 3 -20 9 -20 14 0 5 -10 9 -23 9 -27 0 -77 -21 -77 -33 0 -13
|
||||
-27 -37 -42 -37 -10 0 -12 -11 -10 -40 2 -22 9 -40 16 -40 6 0 17 -9 24 -20 7
|
||||
-11 19 -20 28 -20 11 0 14 -8 12 -26 -3 -29 -17 -39 -61 -49 -15 -3 -25 -10
|
||||
-22 -15 3 -5 -21 -14 -54 -21 l-60 -11 5 -42 c56 -444 70 -582 62 -587 -5 -3
|
||||
-4 -41 3 -97 9 -73 9 -95 -1 -107 -10 -12 -9 -15 4 -15 10 0 15 -4 11 -9 -3
|
||||
-5 5 -17 17 -27 18 -12 19 -15 4 -10 -14 5 -17 2 -12 -9 3 -8 9 -22 13 -31 4
|
||||
-12 2 -15 -8 -12 -8 2 -15 16 -17 31 -5 39 -25 50 -49 27 -12 -10 -23 -17 -26
|
||||
-14 -2 3 -7 -2 -10 -10 -4 -9 -2 -18 3 -21 6 -4 10 -13 10 -22 0 -13 -3 -13
|
||||
-15 -3 -17 14 -38 2 -56 -32 -9 -16 -6 -18 27 -13 21 2 41 10 46 17 7 12 9 11
|
||||
12 -11 0 -5 4 -13 8 -16 4 -4 3 -16 -3 -26 -9 -17 -6 -19 27 -14 21 2 41 10
|
||||
46 17 6 9 10 7 14 -9 7 -25 34 -32 34 -9 0 10 14 16 43 18 41 3 42 4 45 43 2
|
||||
22 7 44 12 49 5 5 58 -26 129 -77 66 -48 125 -87 130 -87 16 0 13 17 -4 24
|
||||
-23 8 -21 105 3 122 20 15 52 18 52 5 0 -5 10 -13 22 -17 19 -6 20 -7 4 -16
|
||||
-12 -7 -14 -13 -7 -22 8 -10 4 -16 -14 -24 -38 -17 -33 -50 11 -68 36 -15 36
|
||||
-16 15 -30 -14 -11 -21 -26 -21 -50 0 -19 -4 -34 -10 -34 -5 0 -10 5 -10 10 0
|
||||
6 -4 10 -8 10 -4 0 -8 -11 -8 -25 0 -31 7 -31 38 0 l25 25 48 -35 c36 -25 52
|
||||
-31 61 -24 7 6 18 8 24 4 6 -4 20 1 30 10 11 10 26 14 38 11 16 -5 19 -2 17
|
||||
25 -2 29 7 37 112 115 62 46 113 88 113 92 0 11 196 153 232 169 15 7 28 17
|
||||
28 23 0 6 4 9 9 6 15 -9 40 28 43 64 2 25 -1 35 -12 35 -37 2 -49 16 -43 48 3
|
||||
18 12 37 19 43 8 6 12 19 8 28 -3 9 -1 16 4 16 12 0 10 34 -3 63 -9 22 11 155
|
||||
28 175 7 9 11 48 9 110 -1 67 2 102 12 116 7 12 17 44 20 71 l7 51 -45 12
|
||||
c-25 6 -46 16 -46 22 0 5 -7 10 -15 10 -9 0 -15 9 -15 21 0 13 -8 23 -21 26
|
||||
-12 3 -16 9 -10 12 6 4 13 21 17 38 5 28 3 31 -25 36 -17 4 -38 4 -46 1 -18
|
||||
-7 -20 -55 -3 -72 8 -8 8 -15 -3 -28 -10 -12 -24 -15 -59 -11 -24 3 -52 1 -62
|
||||
-4 -14 -7 -19 0 -33 44 -10 28 -33 82 -52 120 -35 67 -36 67 -78 67 -41 0 -43
|
||||
-1 -60 -47 -10 -27 -27 -63 -37 -81 -18 -29 -24 -32 -52 -27 -57 12 -66 16
|
||||
-66 35 0 28 -11 51 -21 44 -5 -3 -9 -21 -9 -40 0 -48 -16 -43 -24 8 -5 29 -10
|
||||
38 -15 29 -5 -8 -7 -27 -4 -42 3 -20 -1 -31 -11 -35 -9 -3 -16 -13 -16 -21 0
|
||||
-11 -6 -14 -22 -9 -13 3 -38 6 -56 6 l-33 0 3 48 c3 42 6 47 28 50 23 3 25 7
|
||||
24 49 -1 39 -5 48 -25 55 -13 5 -27 16 -32 24 -10 18 -42 17 -86 -1z m-5 -131
|
||||
c6 -7 16 -14 23 -14 14 0 15 -86 1 -95 -6 -4 -33 -7 -60 -8 -27 -1 -52 -6 -56
|
||||
-10 -17 -17 -34 -6 -34 22 0 63 11 90 41 96 20 5 26 11 22 22 -5 13 -1 15 23
|
||||
9 16 -4 34 -14 40 -22z m509 6 c3 -5 1 -10 -4 -10 -6 0 -11 5 -11 10 0 6 2 10
|
||||
4 10 3 0 8 -4 11 -10z m-167 -97 c46 -6 52 -18 23 -50 -17 -18 -24 -19 -60
|
||||
-10 -49 13 -54 25 -8 21 17 -2 23 -1 12 2 -11 3 -27 8 -35 11 -8 3 -21 7 -29
|
||||
7 -8 1 -16 6 -18 13 -5 13 33 23 57 15 8 -2 34 -7 58 -9z m167 -73 c3 -5 1
|
||||
-10 -4 -10 -6 0 -11 5 -11 10 0 6 2 10 4 10 3 0 8 -4 11 -10z m211 -15 c-21
|
||||
-16 -32 -13 -21 4 3 6 14 11 23 11 15 -1 15 -2 -2 -15z m-786 -21 c0 -31 -23
|
||||
-28 -28 4 -2 15 2 22 12 22 11 0 16 -9 16 -26z m583 -6 c6 -22 1 -38 -11 -38
|
||||
-10 0 -31 48 -24 55 12 12 30 4 35 -17z m137 -8 c-8 -5 -13 -10 -10 -11 3 0
|
||||
14 -2 25 -5 64 -13 156 -23 169 -18 9 3 16 1 16 -5 0 -6 -7 -11 -15 -11 -8 0
|
||||
-15 -7 -15 -15 0 -8 -4 -15 -10 -15 -5 0 -10 4 -10 9 0 5 -15 12 -32 16 -95
|
||||
23 -159 33 -180 27 -26 -6 -23 11 5 24 29 15 79 18 57 4z m-262 -19 c19 -12
|
||||
10 -47 -11 -43 -18 3 -23 -13 -7 -23 12 -7 4 -25 -11 -25 -5 0 -9 14 -9 30 0
|
||||
17 -5 30 -11 30 -5 0 -7 5 -4 10 4 6 11 8 16 5 5 -4 9 1 9 9 0 18 8 20 28 7z
|
||||
m52 -71 l-8 -35 -1 31 c-1 17 2 34 6 37 11 12 12 3 3 -33z m80 24 c0 -8 -4
|
||||
-12 -10 -9 -5 3 -10 10 -10 16 0 5 5 9 10 9 6 0 10 -7 10 -16z m-605 -27 c6
|
||||
-7 55 -28 110 -47 55 -18 107 -40 116 -47 8 -7 21 -13 28 -13 10 0 11 -10 7
|
||||
-35 -6 -32 -3 -39 23 -63 22 -18 31 -36 31 -57 0 -16 7 -43 15 -59 8 -15 15
|
||||
-35 15 -42 0 -8 6 -14 14 -14 7 0 19 -7 26 -15 7 -8 8 -15 3 -15 -6 0 -22 -11
|
||||
-37 -25 -23 -21 -30 -23 -46 -12 -11 6 -20 19 -20 29 0 9 -9 19 -20 23 -12 4
|
||||
-24 21 -30 45 -6 22 -15 42 -20 45 -6 3 -10 13 -10 20 0 18 -31 55 -45 55 -6
|
||||
0 -15 15 -20 32 -8 26 -20 37 -55 51 l-46 19 -33 -31 -33 -31 7 -113 c8 -130
|
||||
10 -133 75 -204 11 -13 20 -35 21 -50 1 -28 15 -74 35 -106 14 -23 51 -30 58
|
||||
-10 5 11 14 14 36 10 16 -4 32 -2 35 2 3 5 16 8 30 6 14 -1 28 2 31 6 8 13 48
|
||||
11 62 -3 7 -7 12 -25 12 -40 0 -21 5 -28 20 -28 16 0 20 7 20 33 0 17 7 41 15
|
||||
51 8 11 15 28 15 38 0 9 8 25 19 35 10 10 21 39 25 68 6 51 26 87 26 48 0 -12
|
||||
-4 -25 -10 -28 -5 -3 -10 -21 -10 -39 0 -20 -8 -40 -20 -51 -11 -10 -20 -25
|
||||
-20 -34 0 -9 -7 -26 -15 -38 -9 -12 -15 -26 -14 -30 5 -31 -3 -55 -21 -60 -12
|
||||
-3 -20 -14 -20 -25 0 -17 5 -19 28 -14 26 6 26 6 8 -9 -11 -8 -23 -15 -28 -15
|
||||
-4 0 -8 -10 -8 -22 0 -18 -2 -20 -9 -9 -5 8 -21 16 -35 18 -20 3 -27 -2 -32
|
||||
-21 -8 -35 -38 -42 -72 -17 l-29 20 -26 -32 c-25 -31 -26 -31 -46 -13 -11 10
|
||||
-20 21 -19 25 2 19 -5 33 -37 65 -19 20 -35 43 -35 52 0 8 -7 29 -16 45 -8 17
|
||||
-13 37 -10 45 8 22 -12 65 -43 94 -16 14 -31 39 -34 55 -3 17 -13 62 -21 100
|
||||
-23 112 -22 268 3 314 8 14 11 38 8 59 -6 34 -6 34 26 28 18 -3 37 -12 42 -19z
|
||||
m593 -36 c15 -47 15 -51 1 -51 -5 0 -7 5 -3 11 4 7 -3 19 -16 29 -15 11 -21
|
||||
23 -17 34 10 26 23 18 35 -23z m69 17 c-3 -8 -6 -5 -6 6 -1 11 2 17 5 13 3 -3
|
||||
4 -12 1 -19z m-36 -51 c-13 -13 -15 11 -4 40 7 16 8 15 11 -6 2 -13 -1 -28 -7
|
||||
-34z m396 1 c-3 -8 -6 -5 -6 6 -1 11 2 17 5 13 3 -3 4 -12 1 -19z m-72 -43
|
||||
c-2 -31 -8 -61 -13 -68 -6 -7 -14 -47 -18 -90 -4 -43 -10 -80 -15 -83 -12 -7
|
||||
2 165 17 210 7 22 11 44 8 48 -5 8 13 38 22 38 1 0 1 -25 -1 -55z m-48 -17
|
||||
c-3 -7 -5 -2 -5 12 0 14 2 19 5 13 2 -7 2 -19 0 -25z m-130 -34 c2 -5 -24 -20
|
||||
-57 -33 -54 -21 -81 -50 -47 -51 6 0 4 -5 -6 -11 -14 -8 -22 -8 -30 0 -14 14
|
||||
-18 69 -6 77 5 3 9 -3 9 -13 0 -14 2 -15 9 -4 5 8 7 21 4 30 -4 14 -3 14 6 1
|
||||
9 -13 15 -12 53 2 45 17 60 18 65 2z m-153 -131 c-4 -16 -10 -30 -13 -33 -3
|
||||
-3 -6 -11 -7 -17 -2 -30 -4 -36 -11 -30 -10 10 -32 -13 -27 -28 3 -7 1 -16 -5
|
||||
-20 -17 -10 -24 21 -11 44 8 16 8 21 -1 21 -7 0 -9 3 -5 8 4 4 12 7 18 7 6 0
|
||||
12 8 14 18 3 21 32 57 46 57 4 0 5 -12 2 -27z m306 -79 c0 -8 -5 -12 -10 -9
|
||||
-6 4 -8 11 -5 16 9 14 15 11 15 -7z m-996 -248 c8 -18 22 -40 33 -47 10 -8 18
|
||||
-20 17 -26 -1 -7 -2 -17 -3 -23 0 -5 -5 -10 -10 -10 -5 0 -7 9 -4 20 3 11 1
|
||||
20 -4 20 -4 0 -17 15 -27 34 -10 19 -25 37 -33 40 -8 3 -11 10 -8 16 11 18 25
|
||||
10 39 -24z m566 -5 c0 -17 -4 -33 -10 -36 -5 -3 -10 -21 -10 -40 0 -40 -8 -65
|
||||
-22 -65 -10 0 -4 70 13 133 12 44 29 49 29 8z m-626 -26 c19 -28 21 -44 4 -27
|
||||
-7 7 -17 8 -30 1 -14 -7 -18 -6 -18 6 0 8 5 15 10 15 6 0 10 5 10 11 0 5 -4 7
|
||||
-10 4 -5 -3 -10 -1 -10 4 0 20 28 11 44 -14z m6 -60 c11 -13 10 -14 -4 -9 -9
|
||||
3 -16 10 -16 15 0 13 6 11 20 -6z m-50 1 c0 -3 -4 -8 -10 -11 -5 -3 -10 -1
|
||||
-10 4 0 6 5 11 10 11 6 0 10 -2 10 -4z m180 -102 c0 -28 -2 -32 -13 -23 -14
|
||||
14 -10 72 4 63 5 -3 9 -21 9 -40z m-216 -90 c17 -16 21 -34 9 -34 -17 1 -45
|
||||
29 -38 39 8 14 11 14 29 -5z m651 -153 c-6 -5 -25 10 -25 20 0 5 6 4 14 -3 8
|
||||
-7 12 -15 11 -17z"/>
|
||||
<path d="M579 1193 c-13 -16 -12 -17 4 -4 9 7 17 15 17 17 0 8 -8 3 -21 -13z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.6 KiB |
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff"
|
||||
}
|
|
@ -10,9 +10,17 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
||||
<!-- These 2 lines make us fullscreen on apple mobile products - remove if you don't like that -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
|
||||
<link rel="icon" href="images/dynmap.ico" type="image/ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="images/icons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="images/icons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="images/icons/favicon-16x16.png">
|
||||
<link rel="manifest" href="images/icons/site.webmanifest">
|
||||
<link rel="mask-icon" href="images/icons/safari-pinned-tab.svg" color="#000000">
|
||||
<link rel="shortcut icon" href="images/icons/favicon.ico">
|
||||
<meta name="msapplication-TileColor" content="#000000">
|
||||
<meta name="msapplication-config" content="images/icons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#000000">
|
||||
|
||||
<script type="text/javascript" src="js/jquery-3.5.1.js?_=${version}-${buildnumber}"></script>
|
||||
<link rel="stylesheet" type="text/css" href="css/leaflet.css?_=${version}-${buildnumber}" />
|
||||
|
@ -54,4 +62,4 @@
|
|||
|
||||
<div id="mcmap"></div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -194,7 +194,9 @@ var DynmapTileLayer = L.TileLayer.extend({
|
|||
if (!url) {
|
||||
this._cachedTileUrls[tileName] = url = this.options.dynmap.getTileUrl(tileName);
|
||||
}
|
||||
|
||||
if (typeof timestamp === 'undefined') {
|
||||
timestamp = this.options.dynmap.inittime
|
||||
}
|
||||
if(typeof timestamp !== 'undefined') {
|
||||
url += (url.indexOf('?') === -1 ? '?timestamp=' + timestamp : '×tamp=' + timestamp);
|
||||
}
|
||||
|
@ -237,7 +239,7 @@ var DynmapTileLayer = L.TileLayer.extend({
|
|||
|
||||
// Some helper functions.
|
||||
zoomprefix: function(amount) {
|
||||
return 'zzzzzzzzzzzzzzzzzzzzzz'.substr(0, amount);
|
||||
return ' zzzzzzzzzzzzzzzzzzzzzzzzzz'.substr(0, amount);
|
||||
},
|
||||
|
||||
getTileInfo: function(coords) {
|
||||
|
|
|
@ -5,13 +5,13 @@ var HDProjection = DynmapProjection.extend({
|
|||
lng = wtp[0] * location.x + wtp[1] * location.y + wtp[2] * location.z;
|
||||
|
||||
return new L.LatLng(
|
||||
-((128 - lat) / (1 << this.options.mapzoomout))
|
||||
-(((128 << this.options.tilescale) - lat) / (1 << this.options.mapzoomout))
|
||||
, lng / (1 << this.options.mapzoomout)
|
||||
, location.y);
|
||||
},
|
||||
fromLatLngToLocation: function(latlon, y) {
|
||||
var ptw = this.options.maptoworld,
|
||||
lat = 128 + latlon.lat * (1 << this.options.mapzoomout),
|
||||
lat = (128 << this.options.tilescale) + latlon.lat * (1 << this.options.mapzoomout),
|
||||
lng = latlon.lng * (1 << this.options.mapzoomout),
|
||||
x = ptw[0] * lng + ptw[1] * lat + ptw[2] * y,
|
||||
z = ptw[6] * lng + ptw[7] * lat + ptw[8] * y;
|
||||
|
@ -25,12 +25,12 @@ var HDMapType = DynmapTileLayer.extend({
|
|||
options: {
|
||||
minZoom: 0,
|
||||
errorTileUrl: 'images/blank.png',
|
||||
tileSize: 128,
|
||||
zoomReverse: true,
|
||||
},
|
||||
initialize: function(options) {
|
||||
options.maxZoom = options.mapzoomin + options.mapzoomout;
|
||||
options.maxNativeZoom = options.mapzoomout;
|
||||
options.tileSize = 128 << (options.tilescale || 0);
|
||||
|
||||
this.projection = new HDProjection($.extend({map: this}, options));
|
||||
|
||||
|
@ -48,7 +48,7 @@ var HDMapType = DynmapTileLayer.extend({
|
|||
// amount == 0 -> ''
|
||||
// amount == 1 -> 'z_'
|
||||
// amount == 2 -> 'zz_'
|
||||
return 'zzzzzzzzzzzzzzzzzzzzzz'.substr(0, amount) + (amount === 0 ? '' : '_');
|
||||
return 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'.substr(0, amount) + (amount === 0 ? '' : '_');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ DynMap.prototype = {
|
|||
formatUrl: function(name, options) {
|
||||
var url = this.options.url[name];
|
||||
$.each(options, function(n,v) {
|
||||
url = url.replace("{" + n + "}", v);
|
||||
url = url.replace("{" + n + "}", encodeURIComponent(v));
|
||||
});
|
||||
return url;
|
||||
},
|
||||
|
@ -592,9 +592,6 @@ DynMap.prototype = {
|
|||
me.selectWorldAndPan(location.world, location, function() {
|
||||
if(completed) completed();
|
||||
});
|
||||
} else {
|
||||
var latlng = me.maptype.getProjection().fromLocationToLatLng(location);
|
||||
me.panToLatLng(latlng, completed);
|
||||
}
|
||||
},
|
||||
panToLayerPoint: function(point, completed) {
|
||||
|
@ -779,8 +776,7 @@ DynMap.prototype = {
|
|||
if (me.followingPlayer !== player) {
|
||||
me.followPlayer(null);
|
||||
}
|
||||
if(player.location.world)
|
||||
me.panToLocation(player.location);
|
||||
me.panToLocation(player.location);
|
||||
});
|
||||
player.menuname.data('sort', player.sort);
|
||||
// Inject into playerlist alphabetically
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue