Compare commits

...

465 Commits
v3.3 ... v3.0

Author SHA1 Message Date
Michael Primm b434f09035 Band-aid up Forge 1.12.2 build 2024-04-29 15:06:37 -05:00
Michael Primm e21198d279 Back to SNAPSHOT 2024-04-28 15:30:36 -05:00
Michael Primm 1d6346b580 Handle tile entity lookup in 1.20.5 2024-04-28 14:01:07 -05:00
Michael Primm e086930133 Update README 2024-04-26 23:12:08 -05:00
Michael Primm 27526e64e5 Migrate to Gradle 8.7, JDK 21 compiler 2024-04-26 22:51:32 -05:00
Michael Primm 21369ec485 Migrate to Gradle 8.7 2024-04-26 22:50:43 -05:00
Michael Primm 120889b500 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2024-04-26 20:54:54 -05:00
Michael Primm 669c75322a Start 1.20.5 code 2024-04-26 20:54:41 -05:00
mikeprimm ea24554033
Merge pull request #4056 from JurgenKuyper/patch-2
Update DynmapBlockState.java
2024-01-23 09:26:06 -06:00
JurgenKuyper b9144e3609
Update DynmapBlockState.java
also hide nether_quartz_ore if hideores is true
2024-01-22 21:11:43 +01:00
Michael Primm 9878719337 Drop older 1.19 Forge and Fabric builds 2023-12-23 15:03:35 -06:00
Michael Primm 6746631758 Back to SNAPSHOT 2023-12-23 14:54:30 -06:00
Michael Primm 23cd60ba0a Switch to beta-4 2023-12-23 09:57:55 -06:00
Michael Primm 328954b256 Handle bogus gamma correction on new GRAY texturepack images 2023-12-22 11:08:10 -06:00
Michael Primm 574a400ada Back to SNAPSHOT 2023-12-15 00:16:37 -06:00
Michael Primm 84ee4cdf0c Prep for 3.7-beta-3 2023-12-14 22:49:51 -06:00
Michael Primm dea6a55acd Add Fabric 1.20.4 build 2023-12-14 22:47:56 -06:00
Michael Primm 87993219bb Add 1.20.3, 1.20.4 blocks 2023-12-14 22:19:53 -06:00
Michael Primm 7cdd90768e Fix S3 PR for 1.12 build 2023-12-12 22:13:44 -06:00
mikeprimm b0e56d3e5a
Merge pull request #4030 from ChimneySwift/generic-s3
Allow generic S3 endpoints for alternative services
2023-12-12 22:02:03 -06:00
Michael Primm 20700c21b8 Fix broken spectator/invisible PR on 1.12 2023-12-12 22:00:23 -06:00
Michael Primm 85885ced0e Add spigot-1.20.4 initial support 2023-12-12 21:22:38 -06:00
mikeprimm 06fbcb8d3d
Merge pull request #4036 from ApliNi/v3.0
Fix SQLite database size keeps increasing
2023-12-12 17:58:59 -06:00
mikeprimm b181607e5a
Merge pull request #4015 from JurgenKuyper/v3.0
implemented hide if spectator
2023-12-01 14:42:45 -06:00
mikeprimm bb1438b3c4
Merge pull request #4023 from Spongecade/patch-1
Update Minecraft wiki link to new domain
2023-12-01 11:43:12 -06:00
ChimneySwift 1ba6dd4683 Bundle xml.bind as this is used by s3-lite 2023-11-17 13:21:35 +10:00
ChimneySwift d16fdc8275 Add override_endpoint setting to configuration files 2023-11-16 22:07:28 +10:00
ChimneySwift 914fc5a10c Allow for custom S3 endpoints 2023-11-16 21:56:35 +10:00
ChimneySwift a669d75de0 Update s3-lite client to 0.0.2-SNAPSHOT version 2023-11-16 21:19:16 +10:00
Jurgen bc0117ac5a implemented hideifspectator switch, fully functional 2023-10-08 11:56:41 +02:00
Spongecade 298b31cdc8
Update Minecraft wiki link to new domain
The Minecraft Fandom wiki has been forked to a new domain: minecraft.wiki. Learn more here: https://minecraft.wiki/w/Minecraft_Wiki:Moving_from_Fandom. This PR updates the old wiki link accordingly.
2023-10-05 16:19:08 -05:00
ApliNi 5244e74d47 PRAGMA auto_vacuum = FULL; 2023-10-03 18:31:51 +08:00
JurgenKuyper 0d15ee5a46
Merge branch 'webbukkit:v3.0' into v3.0 2023-10-01 10:44:26 +02:00
Michael Primm ca80758605 Back to SNAPSHOT 2023-09-28 00:37:31 -05:00
Michael Primm 96554717f1 Switch to 3.7-beta-2 2023-09-27 22:06:10 -05:00
Michael Primm c807861859 Restrict /dmarker file imports to {dynmap-directory}/import 2023-09-27 21:35:40 -05:00
Michael Primm 65cca049ac Fix running on spigot/paper 1.20, 1.20.1 2023-09-27 16:35:44 -05:00
JurgenKuyper 0ba3c8008f
Merge pull request #1 from webbukkit/v3.0
align repo
2023-09-27 22:21:33 +02:00
Jurgen 030a0e1d24 implemented hideifspectator switch, still need to test fabric/forge 2023-09-27 22:22:00 +02:00
Michael Primm 79f354b111 Switch to SecureRandom for web auth token (avoid hugely unlikely
compromise during login register process...).
2023-09-27 12:25:14 -05:00
Michael Primm 92b9016c65 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2023-09-23 18:08:33 -05:00
Michael Primm e6a18f1029 Back to SNAPSHOT 2023-09-23 18:08:23 -05:00
mikeprimm ff87b9dd3e
Merge pull request #4017 from MuriloGhignatti/patch-1
Proper error catching (regarding Quilt)
2023-09-23 18:07:13 -05:00
Michael Primm 2d723afba1 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2023-09-23 17:03:43 -05:00
Michael Primm f5d2244450 Prep for 3.7-beta-1 release 2023-09-23 17:03:32 -05:00
mikeprimm e429a53d27
Update README.md 2023-09-23 13:08:32 -05:00
Michael Primm 169bb81ca7 Add Fabric 1.20.2 initial port 2023-09-23 13:03:21 -05:00
Michael Primm 91c4b23a0e Add forge 1.20.2 2023-09-21 21:31:24 -05:00
Michael Primm e2a5fc80d3 Add spigot 1.20.2 support 2023-09-21 20:13:15 -05:00
Michael Primm 736dd5a290 Add BufferedReader 2023-09-19 21:53:01 -05:00
Michael Primm 7905f76d51 Bump to 3.7-beta-q 2023-09-18 12:55:07 -05:00
Murilo Henrique Ghignatti b97d5045b6
Proper error catching (regarding Quilt)
When the mod is loaded by quilt and you try to get the path using this method an IllegalArgumentException is thrown, I think that quilt is not loading the mod as a file so this is why you are getting this error.
2023-09-13 21:53:17 -03:00
Michael Primm 85012ae478 Add buffered stream to texture reading 2023-09-10 14:49:22 -05:00
Michael Primm d1408b7bfd Adds I/O stream buffering 2023-09-10 10:56:40 -05:00
Jurgen c093a95bc0 implemented hide if spectator 2023-09-03 12:37:58 +02:00
Michael Primm 7ed6728e34 Avoid pan to 0,0 when followed player is not visible 2023-09-02 21:11:47 -05:00
Michael Primm eed1a2b444 Make readonly survive saving (dmap commands) 2023-08-30 10:59:46 -05:00
mikeprimm b8b1e8bd4e
Merge pull request #4007 from Jameskmonger/read-only-map-option
feat: add `readonly` map option
2023-08-30 09:25:06 -05:00
Michael Primm ae164f2993 Restore normal version of chunk handler 2023-08-29 21:49:12 -05:00
mikeprimm ebb9dc00d0
Merge pull request #4011 from stormboomer/Stormboomer-Performance-MySQL-Storage
Drasticly improve zoom tile calculation for larger maps when using MySQL/MariaDB storage Engine
2023-08-29 18:32:58 -05:00
mikeprimm 31d1b400f0
Merge pull request #3990 from Thorinwasher/v3.0
Disable the plugin if on the wrong platform
2023-08-29 13:14:01 -05:00
mikeprimm 105e3887a0
Merge pull request #4005 from JurgenKuyper/v3.0
Update dynmap_style.css
2023-08-29 13:13:20 -05:00
stormboomer 0120c135c4 Added JDK 8 version compatiblity for DynmapCoreAPI.
It seems that this is missing from latest release and causes incompatiblity with older versions. This should resolve this
2023-08-29 20:07:22 +02:00
stormboomer b8166a9122 Remove thread safety implementation for java 17, since it seems to not be needed anymore and improves render time by 8-10% 2023-08-29 13:23:54 +02:00
stormboomer 247e81bc61 Drasticly improve zoom tile calculation for larger maps when using MySQL storage engine. For Larger Tables doing Limit and Offset can have a big Impact on Statement execution because it is an IO heavy task.
This fixes the issue by not doing any limit / offset on the SQL statement but instead query for all the data at once, and let the JDBC handler do the resultset handling.
This can probably be adapted for MSSQL, PostgreSQL and SQLLite.
2023-08-28 08:03:43 +02:00
James Monger fe49d37fa9 feat: update template worlds.txt 2023-08-23 07:21:34 +01:00
James Monger 20592cd805 feat: add `readonly` map option
This option will prevent the map from being updated by the renderer. It can be used if you want a "natural" map, i.e. you want to generate a map and preserve it without being updated with users buildings.
2023-08-23 07:19:03 +01:00
Michael Primm b310a57b64 Shift old spigot/paper support to dynamic load to handle pedantic Paper
loader
2023-08-20 14:38:38 -05:00
JurgenKuyper 6b3e18c351
Update dynmap_style.css
patched issue where the chatbar would drop if login or customlink was enabled, but now the custom link and login overlap if they are set to be in the same area, I don't have enough frontend-knowledge to fix this sadly.
2023-08-18 19:47:13 +02:00
Michael Primm 105d4f1b62 Update bstats library 2023-07-17 18:33:26 -05:00
Thorinwasher 2503dbfdbb Update DynmapPlugin.java 2023-07-10 11:45:27 +02:00
Michael Primm 87d8c73941 Switch to 3.7-SNAPSHOT 2023-07-08 20:09:57 -05:00
Michael Primm cee25bc518 Add workaround for PaperMC's broken Ban API 2023-07-08 15:11:02 -05:00
Michael Primm 3715b114e9 Switch to 3.6 GA release candidate 2023-07-08 13:19:00 -05:00
Michael Primm 881b83b7f1 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2023-06-26 22:18:09 -05:00
Michael Primm 7f6dc1d52c Back to SNAPSHOT 2023-06-26 22:17:42 -05:00
mikeprimm 38ccb50d6a
Merge pull request #3978 from lewismoten/fix-template-spelling
Fix spelling of template
2023-06-21 00:18:11 -05:00
Lewie fa36d3fa38
Fix spelling of template 2023-06-21 00:11:29 -04:00
mikeprimm 983fda35b4
Update README.md 2023-06-20 22:38:58 -05:00
Michael Primm 4e7dcb2cfb Prep for beta-2 2023-06-20 22:32:49 -05:00
Michael Primm e0c02b1fc0 Fix spigot jar shading 2023-06-20 21:06:10 -05:00
Michael Primm b2f04ce112 Back to SNAPSHOT 2023-06-13 21:25:04 -05:00
Michael Primm 57093caa5f Bump to 3.6-beta-1 for release 2023-06-13 14:03:12 -05:00
mikeprimm 551b3adda7
Merge pull request #3974 from kosmolot-mods/fabric-1.20.1
fabric-1.20: mark as compatible with 1.20.1
2023-06-13 09:54:20 -05:00
Kosma Moczek f249ce60b5 fabric-1.20: mark as compatible with 1.20.1 2023-06-12 22:54:36 +02:00
Michael Primm 2f742734d0 Add missing 1.20 blocks 2023-06-10 00:17:07 -04:00
Michael Primm dd81ea2d87 More gradle updates 2023-06-09 23:42:40 -04:00
Michael Primm 126d8e5d05 Avoid jar bloat during shadow building 2023-06-09 03:47:31 -04:00
Michael Primm 6863243d49 More spigot 1.20 updates 2023-06-09 02:49:17 -04:00
Michael Primm 43a86b820c Initial Spigot/Paper 1.20 support 2023-06-09 02:05:17 -04:00
Michael Primm 130953bc12 Make fabric, forge consistent on block type logic 2023-06-08 16:00:47 -05:00
Michael Primm 2d835eaeec Forge 1.20 - start Spigot 1.20 2023-06-08 15:53:11 -05:00
mikeprimm 5aeca48e2b
Merge pull request #3970 from kosmolot-mods/fabric-1.20
Fabric 1.20
2023-06-08 14:32:35 -05:00
Kosma Moczek 427bd6d0ef fabric-1.20: update to 1.20 release 2023-06-08 17:06:16 +02:00
Kosma Moczek 05b751a60e fabric-1.20: update code to 1.20 2023-05-23 01:31:23 +02:00
Kosma Moczek 1450a57aba fabric-1.20: update Fabric to 1.20-pre4 2023-05-23 01:31:23 +02:00
Kosma Moczek 0ee1b6001a fabric-1.20: add to settings.gradle 2023-05-23 01:31:23 +02:00
Kosma Moczek 1d94af6a11 fabric-1.20: fixup package name 2023-05-23 01:31:23 +02:00
Kosma Moczek 8f10ece108 fabric-1.20: copy from fabric-1.19.4 2023-05-22 23:38:46 +02:00
Michael Primm 2456c36649 Update java version 2023-05-10 08:52:53 -05:00
Michael Primm 7bcce9c7e0 Fix cache poisoning on initial tiles on view 2023-05-09 20:47:23 -05:00
Michael Primm 3f2d9dd5df project file updates 2023-05-09 18:30:50 -05:00
Michael Primm 7218e56e5b Get './gradlew eclipse' working again 2023-05-09 18:29:43 -05:00
Michael Primm 4e61fa6b22 Use read API (avoid fixers running) 2023-05-09 14:24:15 -05:00
Michael Primm d1b95c9ae0 Update for 1.19.4 spigot change 2023-05-02 23:30:16 -05:00
Michael Primm 1ccffb7693 3.6-SNAPSHOT 2023-04-29 20:55:22 -05:00
Michael Primm 5bcfe052a5 Prep for 3.5 GA 2023-04-29 16:26:27 -05:00
Michael Primm 8b1b26c570 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2023-04-16 23:53:59 -05:00
Michael Primm 022a031829 Fix >8 bit palette handling 2023-04-16 23:53:45 -05:00
mikeprimm 9c0a1e45fc
Update index.html
Fix iOS viewing
2023-04-11 08:51:08 -05:00
mikeprimm 3b970c7119
Merge pull request #3951 from shaijana/v3.0
Fixed color of cherry-leaves
2023-04-11 08:50:06 -05:00
Shaijana 436dfa22a0 Fixed color of cherry-leaves 2023-03-28 00:34:30 +02:00
Michael Primm bcd4ed617a Missed checkin 2023-03-23 22:28:18 -05:00
Michael Primm ab900740b7 Rework cave shader - make default proportional for variable world height 2023-03-23 13:27:33 -05:00
Michael Primm 76649c6250 Add map data versions for 1.19.2, 1.19.3, 1.19.4 2023-03-21 18:55:29 -05:00
Michael Primm 89d06d158d Back to SNAPSHOT 2023-03-19 00:37:19 -05:00
Michael Primm 2c32cbc0d5 Finish 1.20 preview blocks 2023-03-18 19:52:09 -05:00
Michael Primm cc9f6f0bc4 Add cherry signs 2023-03-18 19:11:32 -05:00
Michael Primm 8dd9e6eb5a Add upcoming cherry wood blocks 2023-03-18 15:06:52 -05:00
Michael Primm ea21f4c4df Add chiseled_bookshelf 2023-03-18 14:44:59 -05:00
Michael Primm 485aec3c1c Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2023-03-18 13:22:08 -05:00
Michael Primm 0f0d4f2ce9 Update block textures 2023-03-18 13:21:50 -05:00
mikeprimm 83d9247f78
Update to beta-3 2023-03-18 11:38:42 -05:00
mikeprimm bfd43d678c
Switch to beta-3 2023-03-18 11:38:08 -05:00
Michael Primm 9a02868534 Update Forge 1.19.3 to also work with Forge 1.19.4 2023-03-16 17:46:18 -05:00
Michael Primm f25d17d3ce Turn fabric 1.19.4 back on 2023-03-16 16:03:57 -05:00
mikeprimm 4a0225bf83
Merge pull request #3946 from kosma/fabric-1.19.4-fix
fabric: fix build issues with 1.19.4 port
2023-03-16 09:44:09 -05:00
Kosma Moczek 7af46a04a6 fabric: fix build issues with 1.19.4 port 2023-03-16 14:20:38 +01:00
Michael Primm 2fd5db2835 Build without fabric 1.19.4 (debug later) 2023-03-16 01:28:30 -05:00
Michael Primm caef8f433e Initial Spigot/Paper 1.19.4 2023-03-16 00:55:32 -05:00
mikeprimm a52ea70b27
Merge pull request #3945 from kosma/fabric-1.19.4
Fabric 1.19.4
2023-03-15 21:05:31 -05:00
Kosma Moczek b4c4b21a04 fabric-1.19.4: adapt for 1.19.4 changes 2023-03-14 22:35:35 +01:00
Kosma Moczek 3bb74d41c2 fabric-1.19.4: update dependencies to 1.19.4 2023-03-14 21:14:14 +01:00
Kosma Moczek ff5f829f16 fabric-1.19.4: remap to yarn 1.19.4+build.1 2023-03-14 21:14:14 +01:00
Kosma Moczek eee5565f86 fabric-1.19.4: add to settings.gradle 2023-03-14 21:14:14 +01:00
Kosma Moczek d85be30e43 fabric-1.19.4: rename 1.19.3 -> 1.19.4 2023-03-14 21:14:14 +01:00
Kosma Moczek 098081f2f3 fabric-1.19.4: copy from fabric-1.19.3 2023-03-14 21:00:03 +01:00
mikeprimm bb0e9dada7
Merge pull request #3934 from Max-42/patch-1
Add comment in configuration.txt
2023-02-27 06:02:04 -06:00
mikeprimm fd2e4ba8c8
Merge pull request #3932 from JurgenKuyper/CaveGradients
implemented user configurable start and stop of cave render
2023-02-27 06:01:35 -06:00
mikeprimm c508711f1c
Merge pull request #3933 from shaijana/v3.0
Added some textures of 1.19.3
2023-02-27 06:00:31 -06:00
Max 52829462e9
fix typo 2023-02-18 22:40:13 +01:00
Max 1a261c6422
add a comment to prevent issues like this: https://github.com/webbukkit/dynmap/issues/2968#issuecomment-652205096 2023-02-16 10:28:44 +01:00
Shaijana bf8a8d9b45 Added some textures of 1.19.3
(Hanging Signs and chiseled bookshelfs are still missing)
2023-02-14 20:47:42 +01:00
Jurgen cc88883dc1 fixed imports, thanks intellij 2023-02-08 19:58:47 +01:00
Jurgen 7b82a9182e implemented user configurable start and stop of cave render 2023-02-08 19:43:20 +01:00
Michael Primm 4efc418691 Back to 3.5-SNAPSHOT 2023-01-29 17:31:17 -06:00
Michael Primm f773175a7b Switch to 3.5-beta-2 2023-01-28 14:56:07 -06:00
mikeprimm dbfcfe03d4
Merge pull request #3906 from jonasbn/spellcheck_gha_update
Update of spellcheck GitHub Action to version 0.29.0
2023-01-25 09:11:45 -06:00
mikeprimm 322c370bbc
Merge pull request #3915 from JurgenKuyper/JarInJarFix
implemented catch to prevent server crash when jar in jar methods are used
2023-01-25 09:10:56 -06:00
mikeprimm 6fd70b65fe
Merge pull request #3910 from JOO200/fix/skinsrestorercompile
Don't use reflections to access SkinsRestorer API
2023-01-25 09:09:25 -06:00
mikeprimm 202625ac23
Merge pull request #3917 from JurgenKuyper/fix_spaces_standalone_markers
Update markers.js
2023-01-25 09:00:32 -06:00
JurgenKuyper 8f62d8e57e
Update markers.js
fixed issue with standalone webserver and spaces in world name, double urlencode changed %20 to %2520 which didn't resolve to the proper address
2023-01-17 14:56:45 +01:00
Jurgen d681f05eeb implemented catch to prevent server crash when jar in jar methods are used 2023-01-12 16:07:17 +01:00
Joo200 ae9e144774 Don't use reflections to access SkinsRestorer API 2023-01-04 15:22:16 +01:00
jonasbn af930cd9d4 Bumped spellcheck version to latest release from version 0.20.0 which is EOL 2022-12-29 12:44:07 +01:00
Michael Primm a6548ec0b7 Drop Fabric and Forge 1.18 builds (just stick with 1.18.2) 2022-12-12 00:45:14 -06:00
Michael Primm 5ddcf1794e Back to SNAPSHOT 2022-12-12 00:40:34 -06:00
Michael Primm 9f9d12a580 Prevent rare shutdown exception 2022-12-11 21:10:52 -06:00
Michael Primm fe100abb51 Prep v3.5-beta-1 release candidate 2022-12-11 17:35:11 -06:00
Michael Primm edf6e256e1 Switch sanitizeHTML to marker load/create/update 2022-12-11 15:44:48 -06:00
Michael Primm 814068cf53 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2022-12-11 15:44:11 -06:00
Michael Primm 287d900047 Shift from Twitter to Mastodon 2022-12-11 15:43:57 -06:00
mikeprimm bc7ecb4f23
Merge pull request #3892 from JOO200/fix/buildfiles
Delete build files in wrong directory
2022-12-11 12:23:54 -06:00
Joo200 0122561150 Delete build files in wrong directory 2022-12-11 18:10:30 +01:00
mikeprimm e168e87bba
Merge pull request #3891 from mastermc05/fabric-1.19.3-colorful-biomes
Add the forgotten colorful biomes to 1.19.3
2022-12-10 14:57:11 -06:00
mastermc05 fe4ff57279 Add the forgotten colorful biomes to 1.19.3 2022-12-10 20:24:34 +02:00
Michael Primm 8af0ad8b8c Add forge 1.19.3 2022-12-08 20:07:05 -06:00
mikeprimm 9e58477f3d
Merge pull request #3888 from kosma/fabric-1.19.3
Fabric 1.19.3
2022-12-08 16:13:24 -06:00
Kosma Moczek 7dee2150b6 fabric-1.19.3: update to full release 2022-12-08 22:36:45 +01:00
Kosma Moczek 7a5440f32e fabric-1.19.3: fix compilation errors 2022-12-08 22:14:09 +01:00
Kosma Moczek c1fcfd15b6 fabric-1.19.3: migrateMappings to 1.19.3-pre2+build.6 2022-12-08 22:14:09 +01:00
Kosma Moczek 743c6ee946 fabric-1.19.3: add as Gradle subproject 2022-12-08 22:14:09 +01:00
Kosma Moczek 68a379cdd2 fabric-1.19.3: update to Loom 1.0-SNAPSHOT 2022-12-08 22:14:09 +01:00
Kosma Moczek 5795ebeac6 fabric-1.19.3: rename package references 2022-12-08 22:14:09 +01:00
Kosma Moczek 0f6c2520ff fabric-1.19.3: rename package folder 2022-12-08 22:14:09 +01:00
Kosma Moczek 2ed13761c4 fabric-1.19.3: copy from fabric-1.19.1 2022-12-08 22:14:09 +01:00
Michael Primm eca305c519 Add initial 1.19.3 for Spigot/PaperMC support 2022-12-08 13:45:18 -06:00
mikeprimm d048aad743
Merge pull request #3857 from Warriorrrr/feature/stringify-async
Stringify json for json file client async
2022-11-29 15:43:31 -06:00
mikeprimm e0cbd1fe8e
Merge pull request #3867 from surfrock66/dynamicfavicon
Add better favicon and code for progressive web apps, to improve shortcuts and icons.
2022-11-29 15:41:33 -06:00
mikeprimm e15f3f8460
Merge pull request #3844 from gmfamily/v3.0
fix(chnk visibility) Use long to avoid int overflow
2022-11-29 15:39:40 -06:00
mikeprimm 26fa3a24c5
Merge pull request #3861 from mastermc05/chunks
Update used paper chunk api
2022-11-29 15:37:59 -06:00
mikeprimm 7d1a273e6d
Merge pull request #3862 from mastermc05/colorful-biomes
Colorful biomes
2022-11-29 15:37:42 -06:00
mikeprimm 9f16074a75
Merge pull request #3863 from mastermc05/fix-colors
Fix colours
2022-11-29 15:36:46 -06:00
mikeprimm 9a8ef557af
Merge pull request #3866 from IMBArator/fix_locale_issue_ModelBlockModelImpl.getLine
fix locale issue in ModelBlockModelImpl getLine (closes:  #3854)
2022-11-29 15:35:49 -06:00
mikeprimm 7f71e7ef9b
Merge pull request #3869 from Captain-Chaos/v3.0
Typo in log message
2022-11-29 15:34:56 -06:00
mastermc05 a5e7ae1013 Fabric 1.16.5: Use BiomeEffectsAccessor to get foliage color 2022-11-18 14:53:24 +02:00
mastermc05 e3911b0d3b Add biome to cache 2022-11-18 13:44:59 +02:00
mastermc05 adc9e273ca Forge 1.16.5 2022-11-18 13:38:14 +02:00
mastermc05 4fdb04725d Forge 1.17.1 2022-11-18 13:32:35 +02:00
mastermc05 d434b33cfb Forge 1.18 2022-11-18 13:32:07 +02:00
mastermc05 1f352e0b11 Forge 1.18.2 2022-11-18 13:31:38 +02:00
mastermc05 ed9fb8614d Forge 1.19 2022-11-18 13:31:11 +02:00
mastermc05 9060c8f32b Forge 1.19.2 2022-11-18 13:30:13 +02:00
mastermc05 a6ead1bc3d Fabric 1.16.4 (1.16.5) 2022-11-18 13:27:07 +02:00
mastermc05 6245a18381 Fabric 1.17.1 2022-11-18 13:18:19 +02:00
mastermc05 0043a1e4fb Fabric 1.18.2 2022-11-18 13:17:21 +02:00
mastermc05 ec3c0e998b Fabric 1.19.1 2022-11-18 13:16:51 +02:00
mastermc05 c643430225 Fabric 1.18 2022-11-18 13:16:29 +02:00
mastermc05 64407e3ce1 Fabric 1.19 2022-11-18 13:16:02 +02:00
mastermc05 0f8174796c Cache biome object, further reduce diff 2022-11-18 13:12:40 +02:00
Captain Chaos 53b3b7c08b Typo in log message 2022-11-11 12:14:27 +01:00
Joseph Gullo ce54de0cd7 Using the icon for dynmap pulled from the patreon/discord, updated the favicon and related files to produce a more refined Progressive Web App which looks better as a bookmark on mobile operating systems. 2022-10-25 13:11:52 -07:00
mastermc05 0ebbc2bbe5 Support for 1.16.5 2022-10-22 14:24:49 +03:00
mastermc05 a40592021f Fix colours 2022-10-15 12:07:07 +03:00
mastermc05 053df84196 Clean up 2022-10-14 16:14:40 +03:00
mastermc05 97a82a3d1b Support 1.17 2022-10-14 16:06:15 +03:00
mastermc05 f34929c6cf Support 1.18 2022-10-14 15:59:20 +03:00
mastermc05 5f29846645 Support 1.18.2 2022-10-14 15:51:08 +03:00
mastermc05 8a8e2ecfcf Abstract for easier multiversion support, reduce diff 2022-10-14 15:37:36 +03:00
mastermc05 1f1a342777 1.19 support 2022-10-14 12:57:23 +03:00
mastermc05 59f44f7425
Change checked class 2022-10-13 21:08:22 +03:00
mastermc05 39adaeca56 Update used paper api 2022-10-10 19:56:37 +03:00
Warrior 8ce85322dd Stringify json for json file client async 2022-10-01 20:39:46 +02:00
Maximilian Zettler a70530edc8 fix locale issue in ModelBlockModelImpl getLine (closes: #3854)
add Locale.US to String.format() where float values are used
2022-09-29 21:02:18 +02:00
gmfamily 61bfe66430
fix(chnk visibility) Use long to avoid int overflow
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
2022-08-31 19:35:18 +02:00
mikeprimm 66fe5d4a8b
Merge pull request #3833 from JurgenKuyper/v3.0
added switch on publicURL in webregister message
2022-08-29 08:29:37 -05:00
mikeprimm 5aaff7cea9
Merge pull request #3836 from JurgenKuyper/templateNotification
added notification on probable misconfiguration of deftemplatesuffix
2022-08-29 08:28:53 -05:00
mikeprimm 686d61c463
Merge pull request #3832 from kosma/dark-forest
Fix dark forest grass color
2022-08-29 08:27:30 -05:00
Jurgen d25040e1cf added notification on probable misconfiguration of deftemplatesuffix 2022-08-21 19:32:59 +02:00
Jurgen adfe0471e3 added switch on publicURL in webregister message 2022-08-19 12:29:14 +02:00
Kosma Moczek e32b8d0f77 BiomeMap: use hardcoded grass color in Dark Forest 2022-08-19 00:24:17 +02:00
mikeprimm 5d867239b2
Merge pull request #3826 from FedUpWith-Tech/v3.0
Fix bad readme links
2022-08-15 09:35:44 -05:00
FedUpWith-Tech aa4d50503e
Fix bad readme links 2022-08-15 09:29:15 -04:00
Mike Primm f96b4d2900 Drop 1.19.0, 1.18.0 for Forge and Fabric from builds 2022-08-14 16:02:47 -05:00
Mike Primm 2a10499325 Switch to v3.5-SNAPSHOT 2022-08-14 16:01:32 -05:00
Mike Primm a6b56dc36e Handle error loading texture pack image without aborting texture pack
load
2022-08-14 12:46:43 -05:00
Mike Primm 0445814ef5 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2022-08-14 00:37:29 -05:00
Mike Primm 4cd915e1ab Switch to 3.4 for release 2022-08-14 00:37:14 -05:00
mikeprimm 171b7c9e54
Merge pull request #3814 from Michele0303/v3.0
multiple cross-site scripting reflected fixed
2022-08-13 23:13:58 -05:00
mikeprimm 7ddecaa566
Merge pull request #3821 from stepech/bump-versions
Bump minimum spigot version, improve armor points counting
2022-08-13 23:12:28 -05:00
mikeprimm a2c1941585
Merge pull request #3820 from mastermc05/v3.0
Try to fix rendering at shutdown
2022-08-13 23:11:23 -05:00
mikeprimm b9e57e4e33
Merge pull request #3823 from kosma/fabric/version-lock
fabric: version-lock fabric.mod.json
2022-08-13 23:10:10 -05:00
Kosma Moczek 058599be77 fabric: version-lock fabric.mod.json
This is intended to reduce user errors where e.g. someone uses the
1.19 jar on 1.19.2. Previously this would lead to unspecific mixin
errors; with this change, a helpful message is shown:

Mod 'Dynmap' (dynmap) 3.4-SNAPSHOT requires version 1.19 of 'Minecraft' (minecraft), but only the wrong version is present: 1.19.2!
2022-08-11 20:13:22 +02:00
mastermc05 36924b4942 Clear scary stacktraces 2022-08-11 11:36:27 +03:00
stepech 0eb2dffac2
Update minimum spigot api, improve armor points counting 2022-08-08 22:40:27 +02:00
Michele e2da0efd8e
Merge branch 'webbukkit:v3.0' into v3.0 2022-08-08 11:26:06 +02:00
mastermc05 36ea4c3938 Merge branch 'v3.0' of https://github.com/mastermc05/dynmap into v3.0 2022-08-08 11:00:35 +03:00
mastermc05 d0e9b66d4a Try to fix https://github.com/webbukkit/dynmap/issues/3819 2022-08-08 11:00:32 +03:00
Mike Primm f89777a0dd Set to SNAPSHOT 2022-08-07 23:53:31 -05:00
Mike Primm 0ab9c9e47b Recycle JDBC connections idle for more than 60 seconds 2022-08-07 23:48:47 -05:00
Mike Primm 3b0814e853 Adjust biome mapping to handle pathological biome counts per segment 2022-08-06 17:48:27 -05:00
Mike Primm 46bd040981 Add Forge 1.19.2 build 2022-08-06 13:10:06 -05:00
Michele0303 8909fea4b1 multiple cross-site scripting reflected fixed 2022-08-02 19:55:09 +02:00
Michele0303 b5ac020a56 Update MySQL_markers.php
cross-site scripting reflected fixed
2022-08-02 19:32:21 +02:00
Mike Primm 7570cf5994 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2022-07-31 12:52:22 -05:00
Mike Primm 85f09b9c2f Prep for 3.4 release 2022-07-31 12:52:09 -05:00
mikeprimm fe97e28401
Merge pull request #3811 from JustZhenya/patch-1
Fix writing non-ascii files to postgresql database
2022-07-31 12:10:48 -05:00
Евгений 43c1159fae
Fix writing non-ascii files to postgresql database
This fixes non-ascii chat messages (for example cyrillic utf8) in PostgreSQL_sendmessage.php

Before fix PostgreSQL_sendmessage.php was returning this:

Fatal error:  Uncaught PDOException: SQLSTATE[22P02]: Invalid text representation: 7 ERROR:  invalid input syntax for type bytea in /opt/minecraft/plugins/dynmap/web/standalone/PostgreSQL_funcs.php:81
Stack trace:
#0 /opt/minecraft/plugins/dynmap/web/standalone/PostgreSQL_funcs.php(81): PDOStatement->execute()
#1 /opt/minecraft/plugins/dynmap/web/standalone/PostgreSQL_funcs.php(99): updateStandaloneFileByServerId()
#2 /opt/minecraft/plugins/dynmap/web/standalone/PostgreSQL_sendmessage.php(60): updateStandaloneFile()
#3 {main}
thrown in /opt/minecraft/plugins/dynmap/web/standalone/PostgreSQL_funcs.php on line 81
2022-07-31 17:06:13 +03:00
Mike Primm b331cfaf27 Fix exception in processEnumMapTiles for Postgres 2022-07-30 21:13:59 -05:00
Mike Primm dc66d12916 Handle null image in MySQL 2022-07-30 18:49:55 -05:00
Mike Primm 082878aade Handle null images 2022-07-30 18:04:28 -05:00
Mike Primm bf8d5eb6cf Fix LIMIT OFFSET order sensitivity (MySQL is kind of dumb...) 2022-07-29 23:10:27 -05:00
mikeprimm 7dabbab8c9
Merge pull request #3809 from kosma/fabric-1.19.1
Fabric 1.19.1
2022-07-29 20:45:11 -05:00
Kosma Moczek e943a26a5b fabric-1.19.1: fix mixins for 1.19.1 2022-07-30 00:30:10 +02:00
Kosma Moczek 1de1c7ce69 fabric-1.19.1: update Minecraft/Fabric version 2022-07-30 00:30:10 +02:00
Kosma Moczek 682ed12c69 fabric-1.19.1: add to settings.gradle 2022-07-30 00:02:27 +02:00
Kosma Moczek dc0296f845 fabric-1.19.1: s/1.19/1.19.1/g 2022-07-29 23:58:21 +02:00
Kosma Moczek 9cd7a3489a fabric-1.19.1: rename fabric_1_19 -> fabric_1_19_1 2022-07-29 23:55:55 +02:00
Kosma Moczek 4ec0d5af37 fabric-1.19.1: copy from fabric-1.19 2022-07-29 23:53:11 +02:00
Mike Primm 47f5779e6f Back to SNAPSHOT 2022-07-26 17:44:10 -05:00
Mike Primm 937ab7cee7 Finish fix 2022-07-24 17:54:09 -05:00
Mike Primm a71348c3c8 Add cooment for https://minecraft.fandom.com/wiki/Data_version 2022-07-24 17:52:00 -05:00
Mike Primm 9648457727 Update chunk version color map 2022-07-24 17:50:33 -05:00
Mike Primm e0619ec650 Add ClientWorld hack 2022-07-24 17:24:19 -05:00
Mike Primm 8e27d5defd Handle AOOBX (not sure why yet) 2022-07-24 17:06:28 -05:00
Mike Primm d88ebb0d20 More resume fixes 2022-07-24 15:32:16 -05:00
Mike Primm e13a515baf More SQLite fixes for scan 2022-07-24 15:11:05 -05:00
Mike Primm 8beba92f8e Fix offset/limit on enums 2022-07-24 14:56:25 -05:00
Mike Primm c80f7adb23 Use limit on enum tiles (for cleaner behavior on purge for large maps) 2022-07-24 13:52:49 -05:00
Mike Primm ab54919956 Add more orderly storage shutdown 2022-07-24 13:09:52 -05:00
Mike Primm e68f628131 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2022-07-22 21:51:51 -05:00
Mike Primm 00a0d3ed37 Set to SNAPSHOT 2022-07-22 21:51:22 -05:00
mikeprimm fc678a056f
Merge pull request #3782 from PssbleTrngle/v3.0
add support for fabric permissions & LuckPerms
2022-07-22 20:59:47 -05:00
mikeprimm 2d6bcbbca2
Merge pull request #3783 from JurgenKuyper/v3.0
updated deprecated interfaces where possible
2022-07-22 20:59:02 -05:00
mikeprimm c248ce3275
Merge pull request #3784 from JurgenKuyper/brick_fix
Mud Brick fix in texture_1.txt
2022-07-22 20:56:51 -05:00
mikeprimm 8f70d5fc3c
Merge pull request #3794 from mastermc05/v3.0
Fix and improve async chunk load
2022-07-22 20:56:24 -05:00
mikeprimm 4d34510c8b
Merge pull request #3797 from reitermarkus/patch-1
Fix broken tiles caused by implicit cast on PHP 8.
2022-07-22 20:54:45 -05:00
mastermc05 075b27a2c4
Merge branch 'webbukkit:v3.0' into v3.0 2022-07-18 17:39:40 +03:00
Mike Primm 425c870895 Update Forge 1.19 to 41.0.100, handle breaking changes by Forge updates 2022-07-17 18:25:42 -05:00
Markus Reiter 8e02c21a36
Fix implicit cast. 2022-07-15 03:30:26 +02:00
Markus Reiter ca5d2f4990
Fix implicit cast. 2022-07-15 03:29:16 +02:00
mastermc05 b933f6b21c Readd fix to copied code 2022-07-07 16:21:22 +03:00
mastermc05 17e60cff40 fix 1.19 2022-07-07 15:34:16 +03:00
mastermc05 8d8a4d088e fix 1.18.2 2022-07-07 15:26:23 +03:00
JurgenKuyper dd789b3a41
Merge branch 'v3.0' into brick_fix 2022-06-21 21:58:36 +02:00
Jurgen a8af8037cb fixed mud_bricks sides so it is no longer transparent. thanks BlargCraft on Reddit. 2022-06-21 19:58:17 +02:00
JurgenKuyper d93a014c99
Merge branch 'webbukkit:v3.0' into v3.0 2022-06-21 13:59:54 +02:00
PssbleTrngle 3b1cbdca09 usercache filename 2022-06-21 12:07:48 +02:00
PssbleTrngle c25945ea13 add missing import 2022-06-21 12:06:26 +02:00
PssbleTrngle 9f865fa5bd fix imports 2022-06-21 11:51:08 +02:00
PssbleTrngle 53f048ac86 add fabric-permissions & luckperms provider 2022-06-21 11:44:17 +02:00
Mike Primm 5818919607 Update forge used in 1.19 build 2022-06-19 13:45:23 -05:00
Mike Primm 69cd5777fc Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2022-06-19 13:35:03 -05:00
Mike Primm a119844669 Set to 3.4-beta-4 2022-06-19 13:34:45 -05:00
mikeprimm 5009159fb4
Merge pull request #3776 from tecdude/patch-1
safari coloured search bar
2022-06-19 13:30:24 -05:00
tecdude 63ab35a9a5
safari coloured search bar
added support for coloured bar in apple safari 15+
2022-06-17 18:47:54 +01:00
mikeprimm e7e8f1c245
Merge pull request #3771 from leon0399/leon0399-patch-1
feat: URI-encode markers loading world name
2022-06-12 11:58:59 -05:00
Mike Primm 57b48ba56f Add 1.19 blocks and textures 2022-06-08 00:42:08 -05:00
Mike Primm 9b7c7aa496 Add initial forge 1.19 2022-06-07 22:04:44 -05:00
Mike Primm 9f20e7a174 Bandaid compile errors in Fabric 1.19 code 2022-06-07 19:29:41 -05:00
mikeprimm 4f1ec1131c
Merge pull request #3769 from kosma/fabric-1.19
Fabric 1.19
2022-06-07 17:21:16 -05:00
Kosma Moczek a39e00ac0f
fabric-1.19: update to 1.19 release
Apply suggestions from code review

Co-authored-by: ThalusA <15985204+ThalusA@users.noreply.github.com>
2022-06-07 23:42:15 +02:00
Mike Primm 9c9c93493e Initial spigot/paper 1.19 port 2022-06-07 12:28:16 -05:00
Leonid Meleshin f8a81ce0ac
feat: URI-encode markers loading world name 2022-06-06 09:51:08 +03:00
Mike Primm 0592bc9f04 Update Gson reference to current spigot level (bogus security flag) 2022-06-05 17:35:50 -05:00
mikeprimm 85d558d932
Merge pull request #3754 from PssbleTrngle/v3.0
Support for fabric-permission-api & LuckPerms
2022-06-05 16:54:31 -05:00
mikeprimm 61a377a3ac
Merge pull request #3740 from CatMoe/v3.0
Implement sign marker for fabric 1.16
2022-06-05 16:53:21 -05:00
mikeprimm 374309e004
Merge pull request #3757 from leon0399/leon0399-patch-1
fix: support special symbols in world names
2022-06-05 16:52:30 -05:00
mikeprimm 6306ae59ea
Merge pull request #3763 from RedstoneFuture/v3.0
Add no-permission message option
2022-06-05 16:51:21 -05:00
mikeprimm 79ed487311
Merge pull request #3766 from TheRijn/patch-1
Set Initial schema version to 4 in PostgreSQL
2022-06-05 16:49:40 -05:00
Marijn Doeve 536b96a5f9
Set Initial schema version to 4 2022-05-30 21:27:42 +02:00
RedstoneFuture 078275d16d Add no-permission message option 2022-05-29 15:28:06 +02:00
Kosma Moczek 24ecd0f72c fabric-1.19: update to 1.19-pre3 2022-05-29 15:07:28 +02:00
Kosma Moczek f02a73bb0d fabric-1.19: do the actual porting work 2022-05-29 14:40:05 +02:00
Kosma Moczek 556051dc9a build.gradle: workaround for Shadow not supporting Java 19 classes 2022-05-29 12:36:11 +02:00
Kosma Moczek f80bb89d96 fabric-1.19: move to Loom 0.12-SNAPSHOT 2022-05-29 12:26:25 +02:00
Kosma Moczek 4e41f1778b settings.gradle: add fabric-1.19 2022-05-29 12:26:25 +02:00
Kosma Moczek 61b03bcdbb fabric-1.19: migrateMappings to 1.19-pre1+build.1 2022-05-29 12:26:25 +02:00
Kosma Moczek 0ba89fefc4 fabric-1.19: rename 1.18.2 -> 1.19 2022-05-29 12:26:25 +02:00
Kosma Moczek 16b30ee40f fabric-1.19: copy from fabric-1.18.2 2022-05-29 12:26:25 +02:00
Kosma Moczek bf4f31c380 gradle: update to 7.4.2 2022-05-29 12:26:25 +02:00
Leonid Meleshin 505d78a8e0
fix: support special symbols in world names
Fix #3755
2022-05-12 19:59:32 +03:00
PssbleTrngle a2951b798d remove debug logging 2022-05-12 15:38:48 +02:00
PssbleTrngle 8763ad91e4 allow op players 2022-05-06 20:02:19 +02:00
PssbleTrngle b2a072c45c LuckPerms permission provider for offline support 2022-05-06 19:55:28 +02:00
PssbleTrngle 5791632d35 add fabric-permission-api provider 2022-05-06 16:48:04 +02:00
Jurgen b3169a6442 updated deprecated interfaces where possible, there are still many left, like ForgeRegistry.BIOME, ForgeRegistry.BLOCK_STATE_IDS, and many more I couln't find a fix for. 2022-05-01 16:24:34 +02:00
CatMoe fa6b729b6e Implement sign marker for fabric 1.16 2022-04-13 06:31:36 +00:00
mikeprimm 9c80489ec6
Merge pull request #3725 from mastermc05/v3.0
Async chunk loading on paper
2022-04-05 23:35:23 -05:00
mastermc05 d4b097ea50 Merge remote-tracking branch 'origin/v3.0' into v3.0 2022-04-01 15:17:17 +03:00
mastermc05 d0a791b634 Clean and finish x2 2022-04-01 15:16:57 +03:00
mastermc05 c3214a81bb
Merge branch 'webbukkit:v3.0' into v3.0 2022-03-31 16:31:38 +03:00
mastermc05 da05fc4675 Clean and finish 2022-03-31 16:18:02 +03:00
mastermc05 790f1f4966 Readd ignore chunk loads 2022-03-31 15:04:36 +03:00
Mike Primm 75789b29a6 Shift CommonAPI initialization forward to ServerAboutToStart 2022-03-30 22:55:49 -05:00
mastermc05 4a97550b63 Parallel process and load plans 2022-03-30 19:37:29 +03:00
mastermc05 c5d113b77a
fix missed 1.16.2 2022-03-30 15:43:55 +03:00
mastermc05 de510108a2
Fix spaces
* fix 1.16.2 spaces

* fix 1.16.4 spaces

* fix 1.16

* fix 1.16.0 x2

* fix 1.17

* fix 1.18.2

* fix 1.18.2 map cache

* fix 1.18.2 map cache p2

* fix 1.18

* fix 1.16.3
2022-03-30 15:39:58 +03:00
Mike Primm 7268db3ed2 Back to SNAPSHOT 2022-03-29 23:29:46 -05:00
Mike Primm 241bc53cb9 Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2022-03-29 22:12:17 -05:00
Mike Primm 5a3a216689 Set to 3.4-beta-3 2022-03-29 22:11:47 -05:00
mastermc05 b0f0a4deb5 First idea implementation 2022-03-29 23:55:05 +03:00
mikeprimm c8801dbb8c
Merge pull request #3696 from webbukkit/generrosity-gradle-notes-tweak
Update README.md
2022-03-27 17:59:36 -05:00
mikeprimm 971a492964
Merge pull request #3703 from davidjpfeiffer/v3.0
Small style improvements to marker labels
2022-03-27 17:59:16 -05:00
Mike Primm d93b836ad0 Add index for Maps table (because SQLite execution planner is stupid) 2022-03-27 13:59:39 -05:00
Mike Primm 7feb9e6735 Fix shading=true/false ambiguity with patch cache lookup 2022-03-26 21:52:40 -05:00
Mike Primm 861d1f8606 Properly bound join in MySQL and SQLite PHP tile lookup 2022-03-26 12:44:41 -05:00
Mike Primm 93c9ab0b5b Band-aid for exceptions in unsupported 'running in client' scenario 2022-03-16 10:24:03 -05:00
Mike Primm ab76953294 Default flags for MS SQL to ";trustServerCertificate=true" 2022-03-10 14:31:31 -06:00
Mike Primm 53b65ab7e4 Add microsoftsql storage type 2022-03-10 14:30:02 -06:00
Mike Primm aec1f0cdb6 Expand maximum zoom level from 16 to 32 2022-03-10 02:24:27 -06:00
Mike Primm 042f387ecf Add fallback for schema upgrade on ancient MySQL servers 2022-03-08 21:17:32 -06:00
FedUpWith-Tech 8aa757b049
Update gibberish.txt
adding more things to ignore
2022-03-06 19:47:17 -05:00
David Pfeiffer 8626d0a1cc
Small style improvements to marker labels 2022-03-05 16:08:27 -08:00
David Pfeiffer f52d2e6c1a
Small style improvements to marker labels 2022-03-05 16:03:44 -08:00
generrosity 015309f8ba
adding additional condensed warnings 2022-03-05 20:37:52 +13:00
FedUpWith-Tech ec6fd59999
Update gibberish.txt 2022-03-03 10:55:56 -05:00
FedUpWith-Tech 04fba09583
Fix typo 2022-03-03 10:53:59 -05:00
Mike Primm a765f728f1 Back to SNAPSHOT 2022-03-02 23:57:18 -06:00
Mike Primm d4d60882fc Back to beta-2 for Forge 1.18.2 2022-03-02 23:02:29 -06:00
Mike Primm 7dd55de52e Add forge 1.18.2 version 2022-03-02 17:50:57 -06:00
Mike Primm 98f2057dd0 Back to SNAPSHOT 2022-03-02 17:27:48 -06:00
Mike Primm 4c2e22e273 Bump to 3.4-beta-2 2022-03-02 09:40:46 -06:00
Mike Primm c3d36dfbf2 Use concurrentmap for dirty_worlds 2022-03-01 08:56:50 -06:00
Mike Primm a86c8a29e1 Update README for 1.18.2 2022-02-28 21:30:51 -06:00
mikeprimm 92af9b5814
Merge pull request #3697 from kosma/fabric-1.18.2
Fabric 1.18.2
2022-02-28 17:55:29 -06:00
Mike Primm d635473d50 First pass of 1.18.2 spigot/paper support 2022-02-28 17:46:40 -06:00
Mike Primm 19ee08716b Back to SNAPSHOT 2022-02-28 17:42:37 -06:00
generrosity 1016c7833b
Update README.md 2022-03-01 10:10:43 +13:00
Kosma Moczek fb37658588 fabric-1.18.2: s/1.18/1.18.2/ 2022-02-28 21:28:17 +01:00
Kosma Moczek 8fee16cd4e fabric-1.18.2: rename fabric_1_18 -> fabric_1_18_2 2022-02-28 21:28:17 +01:00
Kosma Moczek 0d7bfc718e fabric-1.18.2: update build.gradle 2022-02-28 21:28:17 +01:00
Kosma Moczek 0f482489f7 fabric-1.18.2: copy from fabric-1.18 2022-02-28 21:28:17 +01:00
Kosma Moczek cb167d9c04 settings.gradle: add fabric-1.18.2 2022-02-28 21:28:17 +01:00
generrosity e47d6521f4
Update README.md
additions for my dumb ass on how gradle works and where things end up, as this was a recent question in discord too
2022-03-01 08:50:34 +13:00
Mike Primm ed27140fb5 Respin beta 1 as 1.1 2022-02-24 18:04:33 -06:00
Mike Primm 58a2b16217 Drop apache http client, avoid rebase issues in S3 storage code 2022-02-24 17:54:47 -06:00
Mike Primm cf528d22cc Rebase httpcomponents 2022-02-24 16:34:10 -06:00
Mike Primm 9d1b84c9d2 Back to SNAPSHOT 2022-02-23 23:21:14 -06:00
Mike Primm 3cbd198a2a Bump to 3.4-beta-1 2022-02-22 23:17:43 -06:00
Mike Primm 60147e8d16 Handle proxy cascades on X-Forwrded-For 2022-02-22 22:33:33 -06:00
Mike Primm a9b4ace851 Add support for trusted-proxies subnet ranges, handle nested proxies 2022-02-22 22:11:48 -06:00
Mike Primm 037d1803a7 Update candles, candle cake models 2022-02-22 21:14:33 -06:00
Mike Primm 97e5627e0d Fix update URL for AWS S3 2022-02-22 00:57:11 -06:00
Mike Primm f075bf236c Merge branch 'v3.0' of git@github-home:webbukkit/dynmap.git into v3.0 2022-02-22 00:00:38 -06:00
Mike Primm ad226141fe Avoid multithread use of client 2022-02-22 00:00:18 -06:00
Mike Primm 6a95c9231a Zap dynmap_webchat.json if error parsing it 2022-02-21 18:51:31 -06:00
mikeprimm b6d0c816a4
Merge pull request #3685 from ein-stein-chen/fix-biome-color-loading
Fix loading of biome colorschemes
2022-02-21 18:45:25 -06:00
Mike Primm 9066fa0135 Fix transparency handling in WEBP tile generation 2022-02-21 17:57:04 -06:00
Mike Primm 50e6317fa9 Update 1.12.2 2022-02-21 14:32:14 -06:00
Mike Primm f27fbc9f3e Drop forge 1.13.2 (apologies to the 2 folks that might care...) 2022-02-21 14:19:51 -06:00
Mike Primm 1f8bd81894 Drop 1.11.2 from 3.4 build 2022-02-21 14:15:58 -06:00
Mike Primm 10289f85b7 Fix player markers on AWS S3 web 2022-02-20 22:26:30 -06:00
mikeprimm d9c5b78dbc
Merge pull request #3689 from webbukkit/aws-s3
Add first pass of AWS S3 bucket-based storage and web site option
2022-02-20 21:53:02 -06:00
Mike Primm ef045da32f Add prefix path support for AWS S3 website 2022-02-20 21:38:50 -06:00
Mike Primm ea97296684 Get AWS S3 storage based web working 2022-02-20 20:58:21 -06:00
Mike Primm 45bc02cf3a Switch to sdk v2 2022-02-18 00:40:55 -06:00
Mike Primm be43f53d81 Start S3 support 2022-02-17 21:59:53 -06:00
Mike Primm 50dce9b854 Fix comment 2022-02-17 14:35:07 -06:00
Alexander Degenhart ec8d44ea7c
Fix loading of biome colorschemes 2022-02-17 21:33:37 +01:00
Mike Primm 8eb69514f2 Handle bigger tiles in zoom out tiles 2022-02-17 11:33:55 -06:00
Mike Primm 474c5ecca9 Fix render save/restore when tile scale set 2022-02-17 09:15:49 -06:00
Mike Primm a81249539b Avoid exception on bad modellist from DynmapBlockScan 2022-02-16 22:56:36 -06:00
Mike Primm ee78384cdc Add tilescale and defaulttilescal : option for bigger tiles 2022-02-16 21:13:57 -06:00
Mike Primm fb0cceca58 Add eclpse labels for subprojects in Fabric 2022-02-16 21:13:21 -06:00
Mike Primm 3a39688dc8 Avoid exception report during shutdown 2022-02-16 18:43:30 -06:00
Mike Primm 342e67e205 Fix structure blocks 2022-02-16 00:51:03 -06:00
Mike Primm 15b1328c0e Make shutdown InterruptedExceptions not noisy 2022-02-16 00:50:53 -06:00
Mike Primm 04147aadb1 Fix brewing stand model 2022-02-15 22:39:15 -06:00
Mike Primm dacd51aabb Fix handling of flipped texture offsets 2022-02-15 22:39:01 -06:00
Mike Primm 53c4ebf233 Fix dropper model 2022-02-14 23:14:32 -06:00
Mike Primm 19038b3f8b Fix models for spore flower, dried kelp 2022-02-14 23:05:50 -06:00
Mike Primm b43efb1bb6 Fix sunflower model 2022-02-14 22:13:31 -06:00
Mike Primm d0e627607b Fix dripleaf models 2022-02-14 22:01:37 -06:00
Mike Primm 9126cbf649 Update command block, repeating command block, chained command block 2022-02-14 20:58:25 -06:00
Mike Primm 685b4f9e68 Handle doubble flip on texture 2022-02-14 20:27:19 -06:00
Mike Primm de79f8e8bc Fix end rods, and water shading in cauldron 2022-02-14 00:24:57 -06:00
Mike Primm dc129548aa Fix cauldron models 2022-02-13 23:59:17 -06:00
Mike Primm 619167c2df Shade stems using foliage vs grass 2022-02-13 15:01:57 -06:00
Mike Primm 41b5c6f353 Update models for chorus plant and flower 2022-02-12 23:14:52 -06:00
Mike Primm 069c518a7c Fix for nether wart, melot stems, pumpkin stems 2022-02-12 22:23:28 -06:00
Mike Primm 6e2959a63a Update glass pane models 2022-02-12 18:00:31 -06:00
Mike Primm 95c41d91be Pedantic lighting on path 2022-02-12 02:36:44 -06:00
Mike Primm b88aa42853 Fix levers 2022-02-12 02:24:30 -06:00
Mike Primm d941aec6eb Add publicURL setting and '/dynmap url' command 2022-02-12 01:30:00 -06:00
Mike Primm de344869b7 Switch rails to state mapping 2022-02-11 00:40:52 -06:00
Mike Primm 93c84ef15e Reduce patch noise 2022-02-10 23:30:02 -06:00
Mike Primm ff2e1b3b50 Fix scaled textures in ModelBlockModel patches 2022-02-10 22:18:19 -06:00
Mike Primm 7121233462 Label spigot subproject 2022-02-10 15:00:41 -06:00
Mike Primm 8fbc3e3534 More modsupport updates for improved DynmapBlockScan 2022-02-09 22:38:09 -06:00
Mike Primm 611832fa22 More fixes and enhancements for modsupport API 2022-02-08 21:10:58 -06:00
Mike Primm a2f8f9defa Extend modsupport API to deprecate numeric ID, meta values 2022-02-07 20:02:17 -06:00
Mike Primm b3de1dafe3 Tidy up Eclipse workspace 2022-02-07 10:04:12 -06:00
Mike Primm f441cf4ecd Rework lantern with shade=false 2022-02-05 18:55:55 -06:00
Mike Primm 79f27e9565 Add support for shade=false models, switch light/fire blocks over to use
it
2022-02-05 18:24:38 -06:00
Mike Primm cf5f4a0d9e Handle other visibility values in patch definitions 2022-02-05 15:22:00 -06:00
Mike Primm 23b33a7828 Warning cleanup in DynmapCoreAPI 2022-02-05 15:16:58 -06:00
Mike Primm 9d89e56586 General warning cleanup in DynmapCore 2022-02-05 15:16:08 -06:00
Mike Primm d6b1383825 Rework scaffolding models 2022-02-05 14:02:55 -06:00
Mike Primm c83af6dfdc Finish fix for grindstone model 2022-02-05 13:18:34 -06:00
Mike Primm cfcd8fbf3e Allow for clean shutdown 2022-02-05 03:20:22 -06:00
Mike Primm e16b642e0c Allow interrupted exception when shutting down 2022-02-05 03:13:34 -06:00
Mike Primm 1093da7657 Add compassazimuth to perspectives (oveeride for compass orientation)
and 'oldnorth' perspective
2022-02-05 03:11:25 -06:00
Mike Primm 0c34d5a5b5 Shift SQLite to single session in thread pool (it isn't very thread
safe)
2022-02-05 02:05:54 -06:00
Mike Primm 6ce6b4a07f Back to 3.4-SNAPSHOT 2022-02-05 01:52:19 -06:00
Mike Primm b8d08a8ce2 Fix chain models 2022-02-05 00:52:30 -06:00
Mike Primm 88cea7c6e6 Add tables tags, <hr> to sanitizer 2022-02-05 00:02:30 -06:00
Mike Primm e70f2845e8 Make sanizing consistent between initial and updates, add <center> 2022-02-04 23:50:49 -06:00
Mike Primm bdfa148bfb Fix bamboo models 2022-02-04 23:19:47 -06:00
Mike Primm fec2d1af03 Fix webpath update path 2022-02-04 23:14:31 -06:00
Mike Primm 6b208dd038 Add update-webpath-files setting to allow disable of web file updating 2022-02-04 21:47:33 -06:00
Mike Primm 716635c20e Create standalone directory, if needed, during storage startup 2022-02-04 20:09:07 -06:00
Mike Primm e1af7ad952 Fix null check in PHP 2022-02-04 15:40:38 -06:00
Mike Primm 129c666a1a Set for 3.3.2 release 2022-02-04 14:49:20 -06:00
Mike Primm 8e7b57bd89 Handle botched version upgrade on pristine mysql/mariadb 2022-02-03 15:24:57 -06:00
Mike Primm 26a987c98d Fix content type on webp 2022-02-03 15:24:37 -06:00
Mike Primm 8efdbed0b4 Fix SQL in PHP for NewImage 2022-02-03 15:12:59 -06:00
Mike Primm 327833832d Handle rollover from newImage to Image in MySQL PHP 2022-02-03 09:24:36 -06:00
mikeprimm 014760d142
Merge pull request #3647 from DartCZ/v3.0
Include t.newImage after db structure changes
2022-02-03 09:16:36 -06:00
DartCZ b1a320d4bb
Include t.newImage after db structure changes 2022-02-03 13:47:43 +01:00
Mike Primm 4b8fa4a81d Switch slabs and wall torches to state= (test case) 2022-02-02 00:10:48 -06:00
Mike Primm 66082093de Add state= mapping for replacing data= in models and textures
(eventually)
2022-02-01 23:50:58 -06:00
Mike Primm 3c76c3f875 Fix lighting exception in pre 1.13.2 Spigot/Paper 2022-01-31 09:23:40 -06:00
Mike Primm 592ad5028e Fix cocoa model 2022-01-31 08:52:50 -06:00
Mike Primm 1e5cea1829 Switch to 3.4-SNAPSHOT 2022-01-30 17:55:22 -06:00
1505 changed files with 39171 additions and 26434 deletions

View File

@ -36,6 +36,9 @@ ko
patreon
README
Gradle
gradlew
gradle
oldgradle
Curseforge
SpigotMC
PaperMC
@ -55,3 +58,4 @@ JDK
ForgeGradle
Kosma
Kosma's
DEV

View File

@ -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

View File

@ -1,3 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "automatic"
"java.configuration.updateBuildConfiguration": "automatic",
"java.compile.nullAnalysis.mode": "automatic"
}

View File

@ -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 {

View File

@ -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;
@ -286,11 +284,14 @@ 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
s = Sanitizers.FORMATTING.and(Sanitizers.BLOCKS).and(Sanitizers.IMAGES).and(Sanitizers.LINKS).and(Sanitizers.STYLES);
s = Sanitizers.FORMATTING.and(Sanitizers.BLOCKS).and(Sanitizers.IMAGES).and(Sanitizers.LINKS).and(Sanitizers.STYLES).and(Sanitizers.TABLES).and(OLDTAGS);
sanitizer = s;
}
return s.sanitize(html);

View File

@ -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());

View File

@ -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)) {

View File

@ -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;

View File

@ -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,14 +164,22 @@ public class DynmapCore implements DynmapCommonAPI {
private File dataDirectory;
private File tilesDirectory;
private File exportDirectory;
private File importDirectory;
private String plugin_ver;
private MapStorage defaultStorage;
// Read web path
private String webpath;
// And whether to disable web file update
private boolean updatewebpathfiles = true;
private String[] deftriggers = { };
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() {
}
@ -213,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;
}
@ -399,6 +414,11 @@ public class DynmapCore implements DynmapCommonAPI {
configuration = new ConfigurationNode(f);
configuration.load();
// Read web path
webpath = configuration.getString("webpath", "web");
// And whether to disable web file update
updatewebpathfiles = configuration.getBoolean("update-webpath-files", true);
// Check if we are disabling the internal web server (implies external)
isInternalWebServerDisabled = configuration.getBoolean("disable-webserver", false);
@ -412,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")) {
@ -429,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;
@ -476,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);
@ -548,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", "");
@ -673,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");
@ -903,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;
@ -1084,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();
@ -1200,6 +1242,7 @@ public class DynmapCore implements DynmapCommonAPI {
"del-id-for-ip",
"webregister",
"dumpmemory",
"url",
"help"}));
private static class CommandInfo {
@ -1267,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)."),
@ -1324,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"),
@ -1574,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();
@ -1897,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]:"");
@ -1960,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);
}
@ -2062,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;
@ -2126,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);
@ -2152,7 +2207,7 @@ public class DynmapCore implements DynmapCommonAPI {
public String getWebPath() {
return configuration.getString("webpath", "web");
return webpath;
}
public static void setIgnoreChunkLoads(boolean ignore) {
@ -2634,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
@ -2780,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) {
@ -2795,13 +2849,73 @@ 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();
if(df.exists() == false) df.mkdirs();
File ver = new File(df, "version.txt");
File wpath = this.getFile(this.getWebPath());
File webver = new File(wpath, "version.txt");
String prevver = "1.6";
if(ver.exists()) {
String prevwebver = "1.6";
if (ver.exists()) {
Reader ir = null;
try {
ir = new FileReader(ver);
@ -2817,17 +2931,34 @@ public class DynmapCore implements DynmapCommonAPI {
}
}
}
else { // First time, delete old external texture pack
deleteDirectory(new File(df, "texturepacks/standard"));
if (webver.exists()) {
Reader ir = null;
try {
ir = new FileReader(webver);
prevwebver = "";
int c;
while((c = ir.read()) >= 0) {
prevwebver += (char)c;
}
} catch (IOException iox) {
} finally {
if(ir != null) {
try { ir.close(); } catch (IOException iox) {}
}
}
}
String curver = this.getDynmapCoreVersion();
/* If matched, we're good */
if (prevver.equals(curver) && (!curver.endsWith(("-Dev")))) {
if (prevver.equals(curver) && prevwebver.equals(curver) && (!curver.endsWith(("-Dev")))) {
return;
}
// If doing update and web path update is disabled, send warning
if (!this.updatewebpathfiles) {
Log.warning("Update of web interface is disabled, and update is available - UI may not function without updates");
}
/* Get deleted file list */
InputStream in = getClass().getResourceAsStream("/deleted.txt");
if(in != null) {
if (in != null) {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
@ -2843,7 +2974,6 @@ public class DynmapCore implements DynmapCommonAPI {
try { in.close(); } catch (IOException x) {}
}
}
/* Open JAR as ZIP */
ZipFile zf = null;
FileOutputStream fos = null;
@ -2857,24 +2987,45 @@ public class DynmapCore implements DynmapCommonAPI {
while (e.hasMoreElements()) {
ZipEntry ze = e.nextElement();
n = ze.getName();
if(!n.startsWith("extracted/")) continue;
if (!n.startsWith("extracted/")) {
continue;
}
n = n.substring("extracted/".length());
f = new File(df, n);
// If file is going to web path, redirect it to the configured web
if (n.startsWith("web/")) {
// Don't update unless we are allowed to
if (!updatewebpathfiles) {
continue;
}
f = new File(wpath, n.substring("web/".length()));
}
else {
f = new File(df, n);
}
if(ze.isDirectory()) {
f.mkdirs();
}
else {
f.getParentFile().mkdirs();
fos = new FileOutputStream(f);
ins = zf.getInputStream(ze);
int len;
while ((len = ins.read(buf)) >= 0) {
fos.write(buf, 0, len);
}
ins.close();
ins = null;
fos.close();
fos = null;
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);
}
} catch(IOException io) {
Log.severe("Error updating file - " + f.getPath(), io);
} finally {
if (ins != null) {
ins.close();
ins = null;
}
if (fos != null) {
fos.close();
fos = null;
}
}
}
}
} catch (IOException iox) {
@ -2894,7 +3045,7 @@ public class DynmapCore implements DynmapCommonAPI {
}
}
/* Finally, write new version cookie */
/* Finally, write new version cookie to both data folder and web folder*/
Writer out = null;
try {
out = new FileWriter(ver);
@ -2905,7 +3056,21 @@ public class DynmapCore implements DynmapCommonAPI {
try { out.close(); } catch (IOException iox) {}
}
}
Log.info("Extracted files upgraded");
if (this.updatewebpathfiles) {
try {
out = new FileWriter(webver);
out.write(this.getDynmapCoreVersion());
} catch (IOException iox) {
} finally {
if(out != null) {
try { out.close(); } catch (IOException iox) {}
}
}
Log.info("Extracted files upgraded");
}
else {
Log.info("Extracted files upgraded (excluding webpath files)");
}
}
// Server thread tick : nominally, once per 20 Hz tick
public void serverTick(double tps) {

View File

@ -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)) {

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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);
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}
}

View File

@ -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)));

View File

@ -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();

View File

@ -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;

View File

@ -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()) {

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -1,5 +1,6 @@
package org.dynmap.hdmap;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@ -28,6 +29,7 @@ import org.dynmap.renderer.CustomRenderer;
import org.dynmap.renderer.DynmapBlockState;
import org.dynmap.renderer.RenderPatch;
import org.dynmap.renderer.RenderPatchFactory.SideVisible;
import org.dynmap.utils.BlockStateParser;
import org.dynmap.utils.ForgeConfigFile;
import org.dynmap.utils.PatchDefinition;
import org.dynmap.utils.PatchDefinitionFactory;
@ -254,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) {}
@ -295,26 +297,6 @@ public class HDBlockModels {
}
}
private static String getBlockName(String modid, String val) throws NumberFormatException {
char c = val.charAt(0);
if(Character.isLetter(c) || (c == '%') || (c == '&')) {
if ((c == '%') || (c == '&')) {
val = val.substring(1);
}
int off = val.indexOf('+');
if (off > 0) {
val = val.substring(0, off);
}
if (val.indexOf(':') < 0) {
val = modid + ":" + val;
}
return val;
}
else {
throw new NumberFormatException("invalid ID - " + val);
}
}
// Patch index ordering, corresponding to BlockStep ordinal order
public static final int boxPatchList[] = { 1, 4, 0, 3, 2, 5 };
@ -336,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>();
};
@ -358,10 +342,11 @@ public class HDBlockModels {
int cnt = 0;
boolean need_mod_cfg = false;
boolean mod_cfg_loaded = false;
BitSet databits = new BitSet();
String modname = "minecraft";
String modversion = null;
final String mcver = core.getDynmapPluginPlatformVersion();
BlockStateParser bsp = new BlockStateParser();
Map<DynmapBlockState, BitSet> bsprslt;
try {
String line;
ArrayList<HDBlockVolumetricModel> modlist = new ArrayList<HDBlockVolumetricModel>();
@ -372,13 +357,14 @@ public class HDBlockModels {
int layerbits = 0;
int rownum = 0;
int scale = 0;
rdr = new LineNumberReader(new InputStreamReader(in));
while((line = rdr.readLine()) != null) {
rdr = new LineNumberReader(new BufferedReader(new InputStreamReader(in)));
while ((line = rdr.readLine()) != null) {
boolean skip = false;
int lineNum = rdr.getLineNumber();
if ((line.length() > 0) && (line.charAt(0) == '[')) { // If version constrained like
int end = line.indexOf(']'); // Find end
if (end < 0) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + fname + ": bad version limit");
Log.severe("Format error - line " + lineNum + " of " + fname + ": bad version limit");
return;
}
String vertst = line.substring(1, end);
@ -392,62 +378,52 @@ public class HDBlockModels {
}
line = line.substring(end+1);
}
// If we're skipping due to version restriction
if (skip) {
// Comment line
if(line.startsWith("#") || line.startsWith(";")) {
skip = true;
}
else if(line.startsWith("block:")) {
ArrayList<String> blknames = new ArrayList<String>();
databits.clear();
// If we're skipping due to version restriction
if (skip) continue;
// Split off <type>:
int typeend = line.indexOf(':');
String typeid = "";
if (typeend >= 0) {
typeid = line.substring(0, typeend);
line = line.substring(typeend+1).trim();
}
if (typeid.equals("block")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
scale = 0;
line = line.substring(6);
String[] args = line.split(",");
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blknames.add(getBlockName(modname,av[1]));
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
databits.clear();
}
else if (av[1].indexOf('-') > 0) {
String[] sp = av[1].split("-");
int m0 = getIntValue(varvals, sp[0]);
int m1 = getIntValue(varvals, sp[1]);
for (int m = m0; m <= m1; m++) {
databits.set(m);
}
}
else
databits.set(getIntValue(varvals,av[1]));
}
else if(av[0].equals("scale")) {
if(av[0].equals("scale")) {
scale = Integer.parseInt(av[1]);
}
}
bsprslt = bsp.getMatchingStates();
/* If we have everything, build block */
if((blknames.size() > 0) && (scale > 0)) {
if ((bsprslt.size() > 0) && (scale > 0)) {
modlist.clear();
for(String bname : blknames) {
DynmapBlockState bblk = DynmapBlockState.getBaseStateByName(bname);
for (DynmapBlockState bblk : bsprslt.keySet()) {
if (bblk.isNotAir()) {
modlist.add(new HDBlockVolumetricModel(bblk, databits, scale, new long[0], blockset));
modlist.add(new HDBlockVolumetricModel(bblk, bsprslt.get(bblk), scale, new long[0], blockset));
cnt++;
}
else {
Log.severe("Invalid model block name " + bname + " at line " + rdr.getLineNumber());
Log.severe("Invalid model block name " + bblk.blockName + " at line " + lineNum);
}
}
}
else {
Log.severe("Block model missing required parameters = line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Block model missing required parameters = line " + lineNum + " of " + fname);
}
layerbits = 0;
}
else if(line.startsWith("layer:")) {
line = line.substring(6);
else if (typeid.equals("layer")) {
String args[] = line.split(",");
layerbits = 0;
rownum = 0;
@ -455,28 +431,31 @@ public class HDBlockModels {
layerbits |= (1 << Integer.parseInt(a));
}
}
else if(line.startsWith("rotate:")) {
line = line.substring(7);
else if (typeid.equals("rotate")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
String args[] = line.split(",");
String id = null;
int data = -1;
int rot = -1;
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
id = getBlockName(modname,av[1]);
}
if(av[0].equals("data")) { data = getIntValue(varvals,av[1]); }
if(av[0].equals("rot")) { rot = Integer.parseInt(av[1]); }
if (av.length < 2) continue;
if (av[0].equals("rot")) { rot = Integer.parseInt(av[1]); }
}
/* get old model to be rotated */
DynmapBlockState bs = DynmapBlockState.getStateByNameAndIndex(id, (data > 0)?data:0);
if (bs.isAir()) {
Log.severe("Invalid rotate ID: " + id + " on line " + rdr.getLineNumber());
return;
bsprslt = bsp.getMatchingStates();
if (bsprslt.size() != 1) {
Log.severe("Missing rotate source on line " + lineNum);
continue;
}
HDBlockModel mod = models_by_id_data.get(bs.globalStateIndex);
DynmapBlockState basebs = bsprslt.keySet().iterator().next();
BitSet bits = bsprslt.get(basebs);
/* get old model to be rotated */
DynmapBlockState bs = basebs.getState(bits.nextSetBit(0));
if (bs.isAir()) {
Log.severe("Invalid rotate ID: " + bs + " on line " + lineNum);
continue;
}
HDBlockModel mod = models_by_id_data.get(bs.globalStateIndex);
if (modlist.isEmpty()) {
}
else if ((mod != null) && ((rot%90) == 0) && (mod instanceof HDBlockVolumetricModel)) {
@ -512,124 +491,100 @@ public class HDBlockModels {
}
}
else {
Log.severe("Invalid rotate error - line " + rdr.getLineNumber() + " of " + fname);
return;
Log.severe("Invalid rotate error - line " + lineNum + " of " + fname);
continue;
}
}
else if(line.startsWith("patchrotate:")) {
line = line.substring(12);
else if (typeid.equals("patchrotate")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
String args[] = line.split(",");
String id = null;
int data = -1;
int rotx = 0;
int roty = 0;
int rotz = 0;
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
id = getBlockName(modname, av[1]);
}
if(av[0].equals("data")) { data = getIntValue(varvals,av[1]); }
if(av[0].equals("rot")) { roty = Integer.parseInt(av[1]); }
if(av[0].equals("roty")) { roty = Integer.parseInt(av[1]); }
if(av[0].equals("rotx")) { rotx = Integer.parseInt(av[1]); }
if(av[0].equals("rotz")) { rotz = Integer.parseInt(av[1]); }
}
/* get old model to be rotated */
DynmapBlockState bs = DynmapBlockState.getStateByNameAndIndex(id, (data > 0)?data:0);
if (bs.isAir()) {
Log.severe("Invalid patchrotate id: " + id + " on line " + rdr.getLineNumber());
return;
bsprslt = bsp.getMatchingStates();
if (bsprslt.size() != 1) {
Log.severe("Missing rotate source on line " + lineNum);
continue;
}
DynmapBlockState basebs = bsprslt.keySet().iterator().next();
BitSet bits = bsprslt.get(basebs);
/* get old model to be rotated */
DynmapBlockState bs = basebs.getState(bits.nextSetBit(0));
if (bs.isAir()) {
Log.severe("Invalid patchrotate ID: " + bs + " on line " + lineNum);
continue;
}
HDBlockModel mod = models_by_id_data.get(bs.globalStateIndex);
if(pmodlist.isEmpty()) {
if (pmodlist.isEmpty()) {
}
else if((mod != null) && (mod instanceof HDBlockPatchModel)) {
else if ((mod != null) && (mod instanceof HDBlockPatchModel)) {
HDBlockPatchModel pmod = (HDBlockPatchModel)mod;
PatchDefinition patches[] = pmod.getPatches();
PatchDefinition newpatches[] = new PatchDefinition[patches.length];
for(int i = 0; i < patches.length; i++) {
for (int i = 0; i < patches.length; i++) {
newpatches[i] = (PatchDefinition)pdf.getRotatedPatch(patches[i], rotx, roty, rotz, patches[i].textureindex);
}
if(patches.length > max_patches)
if (patches.length > max_patches)
max_patches = patches.length;
for(HDBlockPatchModel patchmod : pmodlist) {
for (HDBlockPatchModel patchmod : pmodlist) {
patchmod.setPatches(newpatches);
}
}
else {
Log.severe("Invalid rotate error - line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Invalid rotate error - line " + lineNum + " of " + fname);
return;
}
}
else if(line.startsWith("ignore-updates:")) {
ArrayList<String> blknames = new ArrayList<String>();
databits.clear();
line = line.substring(line.indexOf(':')+1);
String[] args = line.split(",");
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blknames.add(getBlockName(modname,av[1]));
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
databits.clear();
}
else if (av[1].indexOf('-') > 0) {
String[] sp = av[1].split("-");
int m0 = getIntValue(varvals, sp[0]);
int m1 = getIntValue(varvals, sp[1]);
for (int m = m0; m <= m1; m++) {
databits.set(m);
}
}
else
databits.set(getIntValue(varvals,av[1]));
}
}
for (String nm : blknames) {
DynmapBlockState bbs = DynmapBlockState.getBaseStateByName(nm);
else if (typeid.equals("ignore-updates")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
bsprslt = bsp.getMatchingStates();
for (DynmapBlockState bbs : bsprslt.keySet()) {
if (bbs.isNotAir()) {
for (int i = 0; i < bbs.getStateCount(); i++) {
BitSet bits = bsprslt.get(bbs);
for (int i = bits.nextSetBit(0); i >= 0; i = bits.nextSetBit(i+1)) {
DynmapBlockState bs = bbs.getState(i);
if (databits.isEmpty() || databits.get(i)) {
changeIgnoredBlocks.set(bs.globalStateIndex);
}
changeIgnoredBlocks.set(bs.globalStateIndex);
}
}
else {
Log.severe("Invalid update ignore block name " + nm + " at line " + rdr.getLineNumber());
Log.severe("Invalid update ignore block name " + bbs + " at line " + lineNum);
}
}
}
else if(line.startsWith("#") || line.startsWith(";")) {
}
else if(line.startsWith("enabled:")) { /* Test if texture file is enabled */
line = line.substring(8).trim();
if(line.startsWith("true")) { /* We're enabled? */
else if (typeid.equals("enabled")) { /* Test if texture file is enabled */
if (line.startsWith("true")) { /* We're enabled? */
/* Nothing to do - keep processing */
}
else if(line.startsWith("false")) { /* Disabled */
else if (line.startsWith("false")) { /* Disabled */
return; /* Quit */
}
/* If setting is not defined or false, quit */
else if(config.getBoolean(line, false) == false) {
else if (config.getBoolean(line, false) == false) {
return;
}
else {
Log.info(line + " models enabled");
}
}
else if(line.startsWith("var:")) { /* Test if variable declaration */
line = line.substring(4).trim();
else if (typeid.equals("var")) { /* Test if variable declaration */
String args[] = line.split(",");
for(int i = 0; i < args.length; i++) {
String[] v = args[i].split("=");
if(v.length < 2) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Format error - line " + lineNum + " of " + fname);
return;
}
try {
@ -637,13 +592,13 @@ public class HDBlockModels {
int parmval = config.getInteger(v[0], val); /* Read value, with applied default */
varvals.put(v[0], parmval); /* And save value */
} catch (NumberFormatException nfx) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Format error - line " + lineNum + " of " + fname);
return;
}
}
}
else if(line.startsWith("cfgfile:")) { /* If config file */
File cfgfile = new File(line.substring(8).trim());
else if (typeid.equals("cfgfile")) { /* If config file */
File cfgfile = new File(line);
ForgeConfigFile cfg = new ForgeConfigFile(cfgfile);
if (!mod_cfg_loaded) {
need_mod_cfg = true;
@ -654,9 +609,8 @@ public class HDBlockModels {
mod_cfg_loaded = true;
}
}
else if(line.startsWith("patch:")) {
else if (typeid.equals("patch")) {
String patchid = null;
line = line.substring(6);
String[] args = line.split(",");
double p_x0 = 0.0, p_y0 = 0.0, p_z0 = 0.0;
double p_xu = 0.0, p_yu = 1.0, p_zu = 0.0;
@ -714,7 +668,7 @@ public class HDBlockModels {
p_vmax = Double.parseDouble(av[1]);
}
else if(av[0].equals("UplusVmax")) {
Log.warning("UplusVmax deprecated - use VmaxAtUMax - line " + rdr.getLineNumber() + " of " + fname);
Log.warning("UplusVmax deprecated - use VmaxAtUMax - line " + lineNum + " of " + fname);
p_uplusvmax = Double.parseDouble(av[1]);
}
else if(av[0].equals("VmaxAtUMax")) {
@ -726,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"))
@ -756,58 +716,40 @@ public class HDBlockModels {
}
}
}
else if(line.startsWith("patchblock:")) {
ArrayList<String> blknames = new ArrayList<String>();
databits.clear();
line = line.substring(11);
else if (typeid.equals("patchblock")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
String[] args = line.split(",");
ArrayList<PatchDefinition> patches = new ArrayList<PatchDefinition>();
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blknames.add(getBlockName(modname,av[1]));
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
databits.clear();
}
else if (av[1].indexOf('-') > 0) {
String[] sp = av[1].split("-");
int m0 = getIntValue(varvals, sp[0]);
int m1 = getIntValue(varvals, sp[1]);
for (int m = m0; m <= m1; m++) {
databits.set(m);
}
}
else
databits.set(getIntValue(varvals,av[1]));
}
else if(av[0].startsWith("patch")) {
if(av[0].startsWith("patch")) {
int patchnum0, patchnum1;
String ids = av[0].substring(5);
String[] ids2 = ids.split("-");
if(ids2.length == 1) {
if (ids2.length == 1) {
patchnum0 = patchnum1 = Integer.parseInt(ids2[0]);
}
else {
patchnum0 = Integer.parseInt(ids2[0]);
patchnum1 = Integer.parseInt(ids2[1]);
}
if(patchnum0 < 0) {
Log.severe("Invalid patch index " + patchnum0 + " - line " + rdr.getLineNumber() + " of " + fname);
if (patchnum0 < 0) {
Log.severe("Invalid patch index " + patchnum0 + " - line " + lineNum + " of " + fname);
return;
}
if(patchnum1 < patchnum0) {
Log.severe("Invalid patch index " + patchnum1 + " - line " + rdr.getLineNumber() + " of " + fname);
if (patchnum1 < patchnum0) {
Log.severe("Invalid patch index " + patchnum1 + " - line " + lineNum + " of " + fname);
return;
}
String patchid = av[1];
/* Look up patch by name */
for(int i = patchnum0; i <= patchnum1; i++) {
for (int i = patchnum0; i <= patchnum1; i++) {
PatchDefinition pd = pdf.getPatchByName(patchid, i);
if(pd == null) {
Log.severe("Invalid patch ID " + patchid + " - line " + rdr.getLineNumber() + " of " + fname);
if (pd == null) {
Log.severe("Invalid patch ID " + patchid + " - line " + lineNum + " of " + fname);
return;
}
patches.add(i, pd);
@ -815,57 +757,38 @@ public class HDBlockModels {
}
}
/* If we have everything, build block */
bsprslt = bsp.getMatchingStates();
pmodlist.clear();
if (blknames.size() > 0) {
if (bsprslt.size() > 0) {
PatchDefinition[] patcharray = patches.toArray(new PatchDefinition[patches.size()]);
if(patcharray.length > max_patches)
max_patches = patcharray.length;
for(String nm : blknames) {
DynmapBlockState bs = DynmapBlockState.getBaseStateByName(nm);
for (DynmapBlockState bs : bsprslt.keySet()) {
if (bs.isNotAir()) {
pmodlist.add(new HDBlockPatchModel(bs, databits, patcharray, blockset));
pmodlist.add(new HDBlockPatchModel(bs, bsprslt.get(bs), patcharray, blockset));
cnt++;
}
else {
Log.severe("Invalid patchmodel block name " + nm + " at line " + rdr.getLineNumber());
Log.severe("Invalid patchmodel block name " + bs + " at line " + lineNum);
}
}
}
else {
Log.severe("Patch block model missing required parameters = line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Patch block model missing required parameters = line " + lineNum + " of " + fname);
}
}
// Shortcut for defining a patchblock that is a simple rectangular prism, with sidex corresponding to full block sides
else if(line.startsWith("boxblock:")) {
ArrayList<String> blknames = new ArrayList<String>();
databits.clear();
line = line.substring(9);
String[] args = line.split(",");
else if (typeid.equals("boxblock")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
String[] args = line.split(",");
double xmin = 0.0, xmax = 1.0, ymin = 0.0, ymax = 1.0, zmin = 0.0, zmax = 1.0;
int[] patchlist = boxPatchList;
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blknames.add(getBlockName(modname,av[1]));
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
databits.clear();
}
else if (av[1].indexOf('-') > 0) {
String[] sp = av[1].split("-");
int m0 = getIntValue(varvals, sp[0]);
int m1 = getIntValue(varvals, sp[1]);
for (int m = m0; m <= m1; m++) {
databits.set(m);
}
}
else
databits.set(getIntValue(varvals,av[1]));
}
else if(av[0].equals("xmin")) {
if(av[0].equals("xmin")) {
xmin = Double.parseDouble(av[1]);
}
else if(av[0].equals("xmax")) {
@ -893,59 +816,41 @@ public class HDBlockModels {
}
/* If we have everything, build block */
pmodlist.clear();
if (blknames.size() > 0) {
bsprslt = bsp.getMatchingStates();
if (bsprslt.size() > 0) {
ArrayList<RenderPatch> pd = new ArrayList<RenderPatch>();
CustomRenderer.addBox(pdf, pd, xmin, xmax, ymin, ymax, zmin, zmax, patchlist);
PatchDefinition[] patcharray = new PatchDefinition[pd.size()];
for (int i = 0; i < patcharray.length; i++) {
patcharray[i] = (PatchDefinition) pd.get(i);
}
if(patcharray.length > max_patches)
if (patcharray.length > max_patches)
max_patches = patcharray.length;
for(String nm : blknames) {
DynmapBlockState bs = DynmapBlockState.getBaseStateByName(nm);
for (DynmapBlockState bs : bsprslt.keySet()) {
if (bs.isNotAir()) {
pmodlist.add(new HDBlockPatchModel(bs, databits, patcharray, blockset));
pmodlist.add(new HDBlockPatchModel(bs, bsprslt.get(bs), patcharray, blockset));
cnt++;
}
else {
Log.severe("Invalid boxmodel block name " + nm + " at line " + rdr.getLineNumber());
Log.severe("Invalid boxmodel block name " + bs + " at line " + lineNum);
}
}
}
else {
Log.severe("Box block model missing required parameters = line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Box block model missing required parameters = line " + lineNum + " of " + fname);
}
}
// Shortcut for defining a patchblock that is a simple rectangular prism, with sidex corresponding to full block sides
else if(line.startsWith("boxlist:")) {
ArrayList<String> blknames = new ArrayList<String>();
databits.clear();
line = line.substring(8);
else if (typeid.equals("boxlist")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
String[] args = line.split(",");
ArrayList<BoxLimits> boxes = new ArrayList<BoxLimits>();
for(String a : args) {
for (String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blknames.add(getBlockName(modname,av[1]));
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
databits.clear();
}
else if (av[1].indexOf('-') > 0) {
String[] sp = av[1].split("-");
int m0 = getIntValue(varvals, sp[0]);
int m1 = getIntValue(varvals, sp[1]);
for (int m = m0; m <= m1; m++) {
databits.set(m);
}
}
else
databits.set(getIntValue(varvals,av[1]));
}
else if(av[0].equals("box")) {
if (av[0].equals("box")) {
String[] prms = av[1].split(":");
BoxLimits box = new BoxLimits();
if (prms.length > 0)
@ -973,8 +878,9 @@ public class HDBlockModels {
}
}
/* If we have everything, build block */
bsprslt = bsp.getMatchingStates();
pmodlist.clear();
if (blknames.size() > 0) {
if (bsprslt.size() > 0) {
ArrayList<RenderPatch> pd = new ArrayList<RenderPatch>();
for (BoxLimits bl : boxes) {
@ -984,65 +890,49 @@ public class HDBlockModels {
for (int i = 0; i < patcharray.length; i++) {
patcharray[i] = (PatchDefinition) pd.get(i);
}
if(patcharray.length > max_patches)
if (patcharray.length > max_patches)
max_patches = patcharray.length;
for(String nm : blknames) {
DynmapBlockState bs = DynmapBlockState.getBaseStateByName(nm);
for (DynmapBlockState bs : bsprslt.keySet()) {
if (bs.isNotAir()) {
pmodlist.add(new HDBlockPatchModel(bs, databits, patcharray, blockset));
pmodlist.add(new HDBlockPatchModel(bs, bsprslt.get(bs), patcharray, blockset));
cnt++;
}
else {
Log.severe("Invalid boxlist block name " + nm + " at line " + rdr.getLineNumber());
Log.severe("Invalid boxlist block name " + bs + " at line " + lineNum);
}
}
}
else {
Log.severe("Box list block model missing required parameters = line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Box list block model missing required parameters = line " + lineNum + " of " + fname);
}
}
// Shortcur for building JSON model style
else if(line.startsWith("modellist:")) {
ArrayList<String> blknames = new ArrayList<String>();
databits.clear();
line = line.substring(10);
else if (typeid.equals("modellist")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
String[] args = line.split(",");
ArrayList<ModelBox> boxes = new ArrayList<ModelBox>();
for(String a : args) {
for (String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blknames.add(getBlockName(modname,av[1]));
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
databits.clear();
}
else if (av[1].indexOf('-') > 0) {
String[] sp = av[1].split("-");
int m0 = getIntValue(varvals, sp[0]);
int m1 = getIntValue(varvals, sp[1]);
for (int m = m0; m <= m1; m++) {
databits.set(m);
}
}
else
databits.set(getIntValue(varvals,av[1]));
}
else if(av[0].equals("box")) {
if (av[0].equals("box")) {
// box=from-x/y/z:to-x/y/z/rotx/roty/rotz:<side - upnsew>/<txtidx>/umin/vmin/umax/vmax>:...
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 " + rdr.getLineNumber());
Log.severe("Invalid modellist FROM value (" + prms[0] + " at line " + lineNum);
}
}
if (prms.length > 1) { // Handle to (to-x/y/z or to-x/y/z/rotx/roty/rotz) or to-x/y/z/rotx/roty/rotz/rorigx/rorigy/rorigz
@ -1063,24 +953,32 @@ public class HDBlockModels {
}
}
else {
Log.severe("Invalid modellist TO value (" + prms[1] + " at line " + rdr.getLineNumber());
Log.severe("Invalid modellist TO value (" + prms[1] + " at line " + lineNum);
}
}
// 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)) {
Log.severe("Invalid modellist face '" + v + "' at line " + rdr.getLineNumber());
Log.severe("Invalid modellist face '" + v + "' at line " + lineNum);
continue;
}
if (flds.length > 0) {
String face = flds[0];
side.side = toBlockSide.get(face.substring(0, 1));
if (side.side == null) {
Log.severe("Invalid modellist side value (" + face + ") in '" + v + "' at line " + rdr.getLineNumber());
Log.severe("Invalid modellist side value (" + face + ") in '" + v + "' at line " + lineNum);
continue;
}
if (flds[0].length() > 1) {
@ -1114,78 +1012,70 @@ public class HDBlockModels {
}
}
/* If we have everything, build block */
bsprslt = bsp.getMatchingStates();
pmodlist.clear();
if (blknames.size() > 0) {
if (bsprslt.size() > 0) {
ArrayList<PatchDefinition> pd = new ArrayList<PatchDefinition>();
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, rdr.getLineNumber()));
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;
for(String nm : blknames) {
DynmapBlockState bs = DynmapBlockState.getBaseStateByName(nm);
for (DynmapBlockState bs : bsprslt.keySet()) {
if (bs.isNotAir()) {
pmodlist.add(new HDBlockPatchModel(bs, databits, patcharray, blockset));
pmodlist.add(new HDBlockPatchModel(bs, bsprslt.get(bs), patcharray, blockset));
cnt++;
}
else {
Log.severe("Invalid modellist block name " + nm + " at line " + rdr.getLineNumber());
Log.severe("Invalid modellist block name " + bs + " at line " + lineNum);
}
}
}
else {
Log.severe("Model list block model missing required parameters = line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Model list block model missing required parameters = line " + lineNum + " of " + fname);
}
}
else if(line.startsWith("customblock:")) {
ArrayList<String> blknames = new ArrayList<String>();
HashMap<String,String> custargs = new HashMap<String,String>();
databits.clear();
line = line.substring(12);
else if (typeid.equals("customblock")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
HashMap<String,String> custargs = new HashMap<String,String>();
String[] args = line.split(",");
String cls = null;
for(String a : args) {
for (String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
blknames.add(getBlockName(modname, av[1]));
if (av.length < 2) continue;
if (av[0].equals("id") || av[0].equals("data") || av[0].equals("state")) {
// Skip block state args - should not be bassed to custom block handler
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
databits.clear();
}
else if (av[1].indexOf('-') > 0) {
String[] sp = av[1].split("-");
int m0 = getIntValue(varvals, sp[0]);
int m1 = getIntValue(varvals, sp[1]);
for (int m = m0; m <= m1; m++) {
databits.set(m);
}
}
else
databits.set(getIntValue(varvals,av[1]));
}
else if(av[0].equals("class")) {
else if (av[0].equals("class")) {
cls = av[1];
}
else {
@ -1198,13 +1088,13 @@ public class HDBlockModels {
}
}
/* If we have everything, build block */
if ((blknames.size() > 0) && (cls != null)) {
for (String nm : blknames) {
DynmapBlockState bs = DynmapBlockState.getBaseStateByName(nm);
bsprslt = bsp.getMatchingStates();
if ((bsprslt.size() > 0) && (cls != null)) {
for (DynmapBlockState bs : bsprslt.keySet()) {
if (bs.isNotAir()) {
CustomBlockModel cbm = new CustomBlockModel(bs, databits, cls, custargs, blockset);
CustomBlockModel cbm = new CustomBlockModel(bs, bsprslt.get(bs), cls, custargs, blockset);
if(cbm.render == null) {
Log.severe("Custom block model failed to initialize = line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Custom block model failed to initialize = line " + lineNum + " of " + fname);
}
else {
/* Update maximum texture count */
@ -1216,16 +1106,16 @@ public class HDBlockModels {
cnt++;
}
else {
Log.severe("Invalid custommodel block name " + nm + " at line " + rdr.getLineNumber());
Log.severe("Invalid custommodel block name " + bs + " at line " + lineNum);
}
}
}
else {
Log.severe("Custom block model missing required parameters = line " + rdr.getLineNumber() + " of " + fname);
Log.severe("Custom block model missing required parameters = line " + lineNum + " of " + fname);
}
}
else if(line.startsWith("modname:")) {
String[] names = line.substring(8).split(",");
else if (typeid.equals("modname")) {
String[] names = line.split(",");
boolean found = false;
for(String n : names) {
String[] ntok = n.split("[\\[\\]]");
@ -1254,8 +1144,7 @@ public class HDBlockModels {
return;
}
}
else if(line.startsWith("version:")) {
line = line.substring(line.indexOf(':')+1);
else if (typeid.equals("version")) {
if (!checkVersionRange(mcver, line)) {
return;
}
@ -1281,10 +1170,9 @@ public class HDBlockModels {
}
}
}
if(need_mod_cfg) {
if (need_mod_cfg) {
Log.severe("Error loading configuration file for " + modname);
}
Log.verboseinfo("Loaded " + cnt + " block models from " + fname);
} catch (IOException iox) {
Log.severe("Error reading models.txt - " + iox.toString());

View File

@ -2,11 +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;
@ -82,40 +80,25 @@ public class HDBlockStateTextureMap {
}
// Add block state to table, with given block IDs and state indexes
public void addToTable(List<String> blocknames, BitSet stateidx) {
public void addToTable(Map<DynmapBlockState, BitSet> states) {
/* Add entries to lookup table */
for (String blkname : blocknames) {
DynmapBlockState baseblk = DynmapBlockState.getBaseStateByName(blkname);
for (DynmapBlockState baseblk : states.keySet()) {
if (baseblk.isNotAir()) {
if (stateidx != null) {
for (int stateid = stateidx.nextSetBit(0); stateid >= 0; stateid = stateidx.nextSetBit(stateid+1)) {
DynmapBlockState bs = baseblk.getState(stateid);
if (bs.isAir()) {
Log.warning("Invalid texture block state: " + blkname + ":" + stateid);
continue;
}
if ((this.blockset != null) && (this.blockset.equals("core") == false)) {
HDBlockModels.resetIfNotBlockSet(bs, this.blockset);
}
copyToStateIndex(bs, this, null);
BitSet stateidx = states.get(baseblk);
for (int stateid = stateidx.nextSetBit(0); stateid >= 0; stateid = stateidx.nextSetBit(stateid+1)) {
DynmapBlockState bs = baseblk.getState(stateid);
if (bs.isAir()) {
Log.warning("Invalid texture block state: " + baseblk.blockName + ":" + stateid);
continue;
}
}
else { // Else, loop over all state IDs for given block
for (int stateid = 0; stateid < baseblk.getStateCount(); stateid++) {
DynmapBlockState bs = baseblk.getState(stateid);
if (bs.isAir()) {
Log.warning("Invalid texture block state: " + blkname + ":" + stateid);
continue;
}
if ((this.blockset != null) && (this.blockset.equals("core") == false)) {
HDBlockModels.resetIfNotBlockSet(bs, this.blockset);
}
copyToStateIndex(bs, this, null);
if ((this.blockset != null) && (this.blockset.equals("core") == false)) {
HDBlockModels.resetIfNotBlockSet(bs, this.blockset);
}
copyToStateIndex(bs, this, null);
}
}
else {
Log.warning("Invalid texture block name: " + blkname);
Log.warning("Invalid texture block name: " + baseblk.blockName);
}
}
}

View File

@ -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 };

View File

@ -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));
}
}

View File

@ -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); }

View File

@ -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 */

View File

@ -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

View File

@ -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]);
}

View File

@ -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];

View File

@ -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;

View File

@ -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;
@ -36,6 +37,7 @@ import org.dynmap.common.DynmapCommandSender;
import org.dynmap.exporter.OBJExport;
import org.dynmap.renderer.CustomColorMultiplier;
import org.dynmap.renderer.DynmapBlockState;
import org.dynmap.utils.BlockStateParser;
import org.dynmap.utils.BlockStep;
import org.dynmap.utils.BufferOutputStream;
import org.dynmap.utils.DynIntHashMap;
@ -481,8 +483,7 @@ public class TexturePack {
public static class TextureMap {
private Map<Integer, Integer> key_to_index = new HashMap<Integer, Integer>();
private List<Integer> texture_ids = new ArrayList<Integer>();
private List<String> blocknames = new ArrayList<String>();
private BitSet stateids = new BitSet();
private Map<DynmapBlockState, BitSet> states;
private BlockTransparency trans = BlockTransparency.OPAQUE;
private int colorMult = 0;
private CustomColorMultiplier custColorMult = null;
@ -546,14 +547,13 @@ public class TexturePack {
/**
* Add settings for texture map
*/
private static void addTextureIndex(String id, List<String> blocknames, BitSet stateids, BlockTransparency trans, int colorMult, CustomColorMultiplier custColorMult, String blockset) {
private static void addTextureIndex(String id, Map<DynmapBlockState, BitSet> states, BlockTransparency trans, int colorMult, CustomColorMultiplier custColorMult, String blockset) {
TextureMap idx = textmap_by_id.get(id);
if(idx == null) { /* Add empty one, if not found */
idx = new TextureMap();
textmap_by_id.put(id, idx);
}
idx.blocknames = blocknames;
idx.stateids = stateids;
idx.states = states;
idx.trans = trans;
idx.colorMult = colorMult;
idx.custColorMult = custColorMult;
@ -563,13 +563,13 @@ public class TexturePack {
*/
private static void processTextureMaps() {
for(TextureMap ti : textmap_by_id.values()) {
if(ti.blocknames.isEmpty()) continue;
if(ti.states.isEmpty()) continue;
int[] txtids = new int[ti.texture_ids.size()];
for(int i = 0; i < txtids.length; i++) {
txtids[i] = ti.texture_ids.get(i).intValue();
}
HDBlockStateTextureMap map = new HDBlockStateTextureMap(txtids, null, ti.colorMult, ti.custColorMult, ti.blockset, true, null, ti.trans);
map.addToTable(ti.blocknames, ti.stateids);
map.addToTable(ti.states);
}
}
/**
@ -1255,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];
@ -1268,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;
}
@ -1819,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("#")) {
}
@ -1914,15 +1929,18 @@ public class TexturePack {
String texturemod = null;
String texturepath = null;
boolean terrain_ok = true;
BlockStateParser bsp = new BlockStateParser();
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();
if ((line.length() > 0) && (line.charAt(0) == '[')) { // If version constrained like
int end = line.indexOf(']'); // Find end
if (end < 0) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname + ": bad version limit");
Log.severe("Format error - line " + lineNum + " of " + txtname + ": bad version limit");
return;
}
String vertst = line.substring(1, end);
@ -1936,19 +1954,28 @@ public class TexturePack {
}
line = line.substring(end+1);
}
// If we're skipping due to version restriction
if (skip) {
if (line.startsWith("#") || line.startsWith(";")) {
skip = true;
}
else if(line.startsWith("block:")) {
List<String> blknames = new ArrayList<String>();
BitSet stateids = null;
// If we're skipping due to version restriction
if (skip) continue;
// Split off <type>:
int typeend = line.indexOf(':');
String typeid = "";
if (typeend >= 0) {
typeid = line.substring(0, typeend);
line = line.substring(typeend+1).trim();
}
if (typeid.equals("block")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
int srctxtid = TXTID_TERRAINPNG;
if (!terrain_ok)
srctxtid = TXTID_INVALID; // Mark as not usable
int faces[] = new int[] { TILEINDEX_BLANK, TILEINDEX_BLANK, TILEINDEX_BLANK, TILEINDEX_BLANK, TILEINDEX_BLANK, TILEINDEX_BLANK };
int txtidx[] = new int[] { -1, -1, -1, -1, -1, -1 };
byte layers[] = null;
line = line.substring(6);
BlockTransparency trans = BlockTransparency.OPAQUE;
int colorMult = 0;
int blockColorIdx = -1;
@ -1962,45 +1989,16 @@ public class TexturePack {
if(filetoidx.containsKey(av[1]))
srctxtid = filetoidx.get(av[1]);
else
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname + ": bad texture " + av[1]);
Log.severe("Format error - line " + lineNum + " of " + txtname + ": bad texture " + av[1]);
}
}
// Build ID list : abort rest of processing if no valid values
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
String id = getBlockName(modname, av[1]);
if (id != null) {
blknames.add(id);
}
}
}
if (blknames.size() > 0) {
bsprslt = bsp.getMatchingStates();
if (bsprslt.size() > 0) {
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("data")) {
if(av[1].equals("*")) {
stateids = null;
}
else {
if (stateids == null) { stateids = new BitSet(); }
// See if range
if (av[1].indexOf('-') >= 0) {
String[] tok = av[1].split("-");
int v1 = getIntValue(varvals, tok[0]);
int v2 = getIntValue(varvals, tok[1]);
for (int v = v1; v <= v2; v++) {
stateids.set(v);
}
}
else {
stateids.set(getIntValue(varvals,av[1]));
}
}
}
else if(av[0].equals("top") || av[0].equals("y-") || av[0].equals("face1")) {
if(av[0].equals("top") || av[0].equals("y-") || av[0].equals("face1")) {
faces[BlockStep.Y_MINUS.ordinal()] = parseTextureIndex(filetoidx, srctxtid, av[1]);
}
else if(av[0].equals("bottom") || av[0].equals("y+") || av[0].equals("face0")) {
@ -2030,7 +2028,7 @@ public class TexturePack {
fid0 = fid1 = Integer.parseInt(ids[0]);
}
if((fid0 < 0) || (fid1 < fid0)) {
Log.severe("Texture mapping has invalid face index - " + av[1] + " - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Texture mapping has invalid face index - " + av[1] + " - line " + lineNum + " of " + txtname);
return;
}
int faceToOrd[] = { BlockStep.Y_PLUS.ordinal(), BlockStep.Y_MINUS.ordinal(),
@ -2063,7 +2061,7 @@ public class TexturePack {
if(filetoidx.containsKey(av[1]))
blockColorIdx = filetoidx.get(av[1]);
else
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname + ": bad texture " + av[1]);
Log.severe("Format error - line " + lineNum + " of " + txtname + ": bad texture " + av[1]);
}
else if(av[0].startsWith("patch")) {
int patchid0, patchid1;
@ -2077,7 +2075,7 @@ public class TexturePack {
patchid0 = patchid1 = Integer.parseInt(ids[0]);
}
if((patchid0 < 0) || (patchid1 < patchid0)) {
Log.severe("Texture mapping has invalid patch index - " + av[1] + " - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Texture mapping has invalid patch index - " + av[1] + " - line " + lineNum + " of " + txtname);
return;
}
if(faces.length <= patchid1) {
@ -2099,7 +2097,7 @@ public class TexturePack {
trans = BlockTransparency.valueOf(av[1]);
if(trans == null) {
trans = BlockTransparency.OPAQUE;
Log.severe("Texture mapping has invalid transparency setting - " + av[1] + " - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Texture mapping has invalid transparency setting - " + av[1] + " - line " + lineNum + " of " + txtname);
}
/* For leaves, base on leaf transparency setting */
if(trans == BlockTransparency.LEAVES) {
@ -2115,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());
}
@ -2127,7 +2125,7 @@ public class TexturePack {
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].startsWith("layer")) {
if (av[0].startsWith("layer")) {
if(layers == null) {
layers = new byte[faces.length];
Arrays.fill(layers, (byte)-1);
@ -2145,21 +2143,21 @@ public class TexturePack {
}
}
/* If we have everything, build block */
if(blknames.size() > 0) {
if (bsprslt.size() > 0) {
Integer colorIndex = (blockColorIdx >= 0)?(blockColorIdx + IMG_CNT):null;
HDBlockStateTextureMap map = new HDBlockStateTextureMap(faces, layers, colorMult, custColorMult, blockset, stdrot, colorIndex, trans);
map.addToTable(blknames, stateids);
map.addToTable(bsprslt);
cnt++;
}
else {
Log.severe("Texture mapping missing required parameters = line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Texture mapping missing required parameters = line " + lineNum + " of " + txtname);
}
}
}
else if(line.startsWith("copyblock:")) {
List<String> blknames = new ArrayList<String>();
BitSet stateids = null;
line = line.substring(line.indexOf(':')+1);
else if (typeid.equals("copyblock")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
String[] args = line.split(",");
String srcname = null;
int srcmeta = 0;
@ -2167,33 +2165,7 @@ public class TexturePack {
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
String id = getBlockName(modname, av[1]);
if (id != null) {
blknames.add(id);
}
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
stateids = null; // Set all
}
else {
if (stateids == null) { stateids = new BitSet(); }
// See if range
if (av[1].indexOf('-') >= 0) {
String[] tok = av[1].split("-");
int v1 = getIntValue(varvals, tok[0]);
int v2 = getIntValue(varvals, tok[1]);
for (int v = v1; v <= v2; v++) {
stateids.set(v);
}
}
else {
stateids.set(getIntValue(varvals,av[1]));
}
}
}
else if(av[0].equals("srcid")) {
if(av[0].equals("srcid")) {
srcname = getBlockName(modname, av[1]);
}
else if(av[0].equals("srcmeta")) {
@ -2203,7 +2175,7 @@ public class TexturePack {
trans = BlockTransparency.valueOf(av[1]);
if(trans == null) {
trans = BlockTransparency.OPAQUE;
Log.severe("Texture mapping has invalid transparency setting - " + av[1] + " - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Texture mapping has invalid transparency setting - " + av[1] + " - line " + lineNum + " of " + txtname);
}
/* For leaves, base on leaf transparency setting */
if(trans == BlockTransparency.LEAVES) {
@ -2215,49 +2187,42 @@ public class TexturePack {
}
}
/* If we have everything, build block */
if((blknames.size() > 0) && (srcname != null)) {
bsprslt = bsp.getMatchingStates();
if ((bsprslt.size() > 0) && (srcname != null)) {
DynmapBlockState srcblk = DynmapBlockState.getStateByNameAndIndex(srcname, srcmeta);
HDBlockStateTextureMap map = null;
if (srcblk != null) map = HDBlockStateTextureMap.getByBlockState(srcblk);
if (map == null) {
Log.severe("Copy of texture mapping failed = line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Copy of texture mapping failed = line " + lineNum + " of " + txtname);
}
else {
for (String blkname : blknames) {
DynmapBlockState dblk = DynmapBlockState.getBaseStateByName(blkname);
if (stateids == null) {
for (int sid = 0; sid < dblk.getStateCount(); sid++) {
DynmapBlockState dblk2 = dblk.getState(sid);
HDBlockStateTextureMap.copyToStateIndex(dblk2, map, trans);
}
}
else {
for (int stateid = stateids.nextSetBit(0); stateid >= 0; stateid = stateids.nextSetBit(stateid+1)) {
DynmapBlockState dblk2 = dblk.getState(stateid);
HDBlockStateTextureMap.copyToStateIndex(dblk2, map, trans);
}
for (DynmapBlockState bblk : bsprslt.keySet()) {
BitSet stateids = bsprslt.get(bblk);
for (int stateid = stateids.nextSetBit(0); stateid >= 0; stateid = stateids.nextSetBit(stateid+1)) {
DynmapBlockState dblk2 = bblk.getState(stateid);
HDBlockStateTextureMap.copyToStateIndex(dblk2, map, trans);
}
}
cnt++;
}
}
else {
Log.severe("Texture mapping copy missing required parameters = line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Texture mapping copy missing required parameters = line " + lineNum + " of " + txtname);
}
}
else if(line.startsWith("addtotexturemap:")) {
else if (typeid.equals("addtotexturemap")) {
int srctxtid = -1;
String mapid = null;
line = line.substring(line.indexOf(':') + 1);
String[] args = line.split(",");
for(String a : args) {
for (String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
else if(av[0].equals("txtid")) {
if(filetoidx.containsKey(av[1]))
srctxtid = filetoidx.get(av[1]);
else
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Format error - line " + lineNum + " of " + txtname);
}
else if(av[0].equals("mapid")) {
mapid = av[1];
@ -2276,14 +2241,14 @@ public class TexturePack {
}
}
else {
Log.severe("Missing mapid - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Missing mapid - line " + lineNum + " of " + txtname);
}
}
else if(line.startsWith("texturemap:")) {
List<String> blknames = new ArrayList<String>();
BitSet stateids = null;
else if (typeid.equals("texturemap")) {
// Parse block states
bsp.processLine(modname, line, lineNum, varvals);
String mapid = null;
line = line.substring(line.indexOf(':') + 1);
BlockTransparency trans = BlockTransparency.OPAQUE;
int colorMult = 0;
CustomColorMultiplier custColorMult = null;
@ -2291,40 +2256,14 @@ public class TexturePack {
for(String a : args) {
String[] av = a.split("=");
if(av.length < 2) continue;
if(av[0].equals("id")) {
String id = getBlockName(modname, av[1]);
if (id != null) {
blknames.add(id);
}
}
else if(av[0].equals("mapid")) {
if(av[0].equals("mapid")) {
mapid = av[1];
}
else if(av[0].equals("data")) {
if(av[1].equals("*")) {
stateids = null;
}
else {
if (stateids == null) { stateids = new BitSet(); }
// See if range
if (av[1].indexOf('-') >= 0) {
String[] tok = av[1].split("-");
int v1 = getIntValue(varvals, tok[0]);
int v2 = getIntValue(varvals, tok[1]);
for (int v = v1; v <= v2; v++) {
stateids.set(v);
}
}
else {
stateids.set(getIntValue(varvals,av[1]));
}
}
}
else if(av[0].equals("transparency")) {
trans = BlockTransparency.valueOf(av[1]);
if(trans == null) {
trans = BlockTransparency.OPAQUE;
Log.severe("Texture mapping has invalid transparency setting - " + av[1] + " - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Texture mapping has invalid transparency setting - " + av[1] + " - line " + lineNum + " of " + txtname);
}
/* For leaves, base on leaf transparency setting */
if(trans == BlockTransparency.LEAVES) {
@ -2340,23 +2279,23 @@ 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());
}
}
}
/* If we have everything, build texture map */
if((blknames.size() > 0) && (mapid != null)) {
addTextureIndex(mapid, blknames, stateids, trans, colorMult, custColorMult, blockset);
bsprslt = bsp.getMatchingStates();
if ((bsprslt.size() > 0) && (mapid != null)) {
addTextureIndex(mapid, bsprslt, trans, colorMult, custColorMult, blockset);
}
else {
Log.severe("Texture map missing required parameters = line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Texture map missing required parameters = line " + lineNum + " of " + txtname);
}
}
else if(line.startsWith("texturefile:") || line.startsWith("texture:")) {
boolean istxt = line.startsWith("texture:");
line = line.substring(line.indexOf(':')+1);
else if (typeid.equals("texturefile") || typeid.equals("texture")) {
boolean istxt = typeid.equals("texture");
String[] args = line.split(",");
int xdim = 16, ydim = 16;
String fname = null;
@ -2391,7 +2330,7 @@ public class TexturePack {
else if(aval[0].equals("format")) {
fmt = TileFileFormat.valueOf(aval[1].toUpperCase());
if(fmt == null) {
Log.severe("Invalid format type " + aval[1] + " - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Invalid format type " + aval[1] + " - line " + lineNum + " of " + txtname);
return;
}
}
@ -2411,14 +2350,11 @@ public class TexturePack {
}
}
else {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Format error - line " + lineNum + " of " + txtname);
return;
}
}
else if(line.startsWith("#") || line.startsWith(";")) {
}
else if(line.startsWith("enabled:")) { /* Test if texture file is enabled */
line = line.substring(8).trim();
else if (typeid.equals("enabled")) { /* Test if texture file is enabled */
if(line.startsWith("true")) { /* We're enabled? */
/* Nothing to do - keep processing */
}
@ -2433,13 +2369,12 @@ public class TexturePack {
Log.info(line + " textures enabled");
}
}
else if(line.startsWith("var:")) { /* Test if variable declaration */
line = line.substring(4).trim();
else if (typeid.equals("var")) { /* Test if variable declaration */
String args[] = line.split(",");
for(int i = 0; i < args.length; i++) {
String[] v = args[i].split("=");
if(v.length < 2) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Format error - line " + lineNum + " of " + txtname);
return;
}
try {
@ -2447,16 +2382,16 @@ public class TexturePack {
int parmval = config.getInteger(v[0], val); /* Read value, with applied default */
varvals.put(v[0], parmval); /* And save value */
} catch (NumberFormatException nfx) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname + ": " + nfx.getMessage());
Log.severe("Format error - line " + lineNum + " of " + txtname + ": " + nfx.getMessage());
return;
}
}
}
else if(line.startsWith("cfgfile:")) { /* If config file */
else if (typeid.equals("cfgfile")) { /* If config file */
if (!mod_cfg_loaded) {
mod_cfg_needed = true;
}
File cfgfile = new File(line.substring(8).trim());
File cfgfile = new File(line);
ForgeConfigFile cfg = new ForgeConfigFile(cfgfile);
if(cfg.load()) {
cfg.addBlockIDs(varvals);
@ -2464,8 +2399,8 @@ public class TexturePack {
mod_cfg_loaded = true;
}
}
else if(line.startsWith("modname:")) {
String[] names = line.substring(8).split(",");
else if (typeid.equals("modname")) {
String[] names = line.split(",");
boolean found = false;
for(String n : names) {
String[] ntok = n.split("[\\[\\]]");
@ -2494,17 +2429,16 @@ public class TexturePack {
}
if(!found) return;
}
else if(line.startsWith("texturemod:")) {
texturemod = line.substring(line.indexOf(':')+1).trim();
else if (typeid.equals("texturemod")) {
texturemod = line;
}
else if(line.startsWith("texturepath:")) {
texturepath = line.substring(line.indexOf(':')+1).trim();
else if (typeid.equals("texturepath")) {
texturepath = line.trim();
if (texturepath.charAt(texturepath.length()-1) != '/') {
texturepath += "/";
}
}
else if(line.startsWith("biome:")) {
line = line.substring(6).trim();
else if (typeid.equals("biome")) {
String args[] = line.split(",");
int id = 0;
int grasscolormult = -1;
@ -2515,7 +2449,7 @@ public class TexturePack {
for(int i = 0; i < args.length; i++) {
String[] v = args[i].split("=");
if(v.length < 2) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname);
Log.severe("Format error - line " + lineNum + " of " + txtname);
return;
}
if(v[0].equals("id")) {
@ -2540,7 +2474,7 @@ public class TexturePack {
if(id > 0) {
BiomeMap b = BiomeMap.byBiomeID(id); /* Find biome */
if(b == null) {
Log.severe("Format error - line " + rdr.getLineNumber() + " of " + txtname + ": " + id);
Log.severe("Format error - line " + lineNum + " of " + txtname + ": " + id);
}
else {
if(foliagecolormult != -1)
@ -2556,14 +2490,12 @@ public class TexturePack {
}
}
}
else if(line.startsWith("version:")) {
line = line.substring(line.indexOf(':')+1);
else if (typeid.equals("version")) {
if (!HDBlockModels.checkVersionRange(mcver, line)) {
return;
}
}
else if(line.startsWith("noterrainpng:")) {
line = line.substring(line.indexOf(':')+1);
else if (typeid.equals("noterrainpng")) {
if (line.startsWith("true")) {
terrain_ok = false;
}
@ -2626,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) {

View File

@ -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 */

View File

@ -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) {

View File

@ -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+)

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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();

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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");

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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"));
}

View File

@ -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() {}
}
}

View File

@ -1,7 +1,5 @@
package org.dynmap.storage;
import org.dynmap.MapType.ImageEncoding;
public interface MapStorageTileSearchEndCB {
/**
* Callback for end of tile enumeration calls

View File

@ -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();
}
}
}
}

View File

@ -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

View File

@ -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);
}
@ -326,6 +341,10 @@ public class MySQLMapStorage extends MapStorage {
cfgfile.delete(); // Zap file (in case we left junk from last time)
return true;
}
// During initial startup, this can happen before baseStandaloneDir is setup
if (!baseStandaloneDir.exists()) {
baseStandaloneDir.mkdirs();
}
FileWriter fw = null;
try {
fw = new FileWriter(cfgfile);
@ -366,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()) {
@ -375,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); }
}
@ -414,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;
@ -453,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);
}
@ -477,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 (4)");
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;
@ -498,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;
@ -516,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;
@ -534,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;
@ -546,13 +586,53 @@ public class MySQLMapStorage extends MapStorage {
try {
Log.info("Updating database schema from version = " + version);
c = getConnection();
doUpdate(c, "ALTER TABLE " + tableTiles + " ADD COLUMN NewImage MEDIUMBLOB, ALGORITHM=INPLACE, LOCK=NONE");
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();
boolean inplace = false;
if (rs.next()) { // Got nothing?
inplace = true;
}
rs.close();
stmt.close();
if (!inplace) {
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;
@ -565,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) {
@ -606,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;
@ -717,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"));
@ -729,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);
}
@ -774,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);
}
@ -813,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);
}
@ -840,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);
}
@ -865,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);
}
@ -912,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) {} }
@ -939,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);
}
@ -985,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) {} }
@ -1012,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);
}
@ -1068,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);
}
@ -1118,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) {} }

View File

@ -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);
}
@ -313,6 +326,10 @@ public class PostgreSQLMapStorage extends MapStorage {
cfgfile.delete(); // Zap file (in case we left junk from last time)
return true;
}
// During initial startup, this can happen before baseStandaloneDir is setup
if (!baseStandaloneDir.exists()) {
baseStandaloneDir.mkdirs();
}
FileWriter fw = null;
try {
fw = new FileWriter(cfgfile);
@ -363,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); }
}
@ -400,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;
@ -439,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);
}
@ -463,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;
@ -487,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;
@ -505,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;
@ -517,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) {
@ -557,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;
@ -651,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);
}
@ -724,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);
}
@ -763,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);
}
@ -790,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);
}
@ -815,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);
}
@ -862,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) {} }
@ -889,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);
}
@ -935,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) {} }
@ -962,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);
}
@ -1018,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);
}
@ -1068,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) {} }

View File

@ -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);
}
}

View File

@ -0,0 +1,236 @@
package org.dynmap.utils;
import org.dynmap.Log;
import org.dynmap.renderer.DynmapBlockState;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// Utility class used for parsing block name and block state identity from lines in model and texture files
public class BlockStateParser {
private HashMap<DynmapBlockState, BitSet> basestates;
private ArrayList<String> badtokens;
private String modid;
private int linenum;
private boolean filtered;
public BlockStateParser() {
}
/**
* Process new line into list of matching states Produce list of block states
* matching the fields in the provided line (specifically the portion after the
* '<type>:" prefix) at the stsrt of the line. Processes id=<block ID> or
* id=<nlock Name> or id=<modid>:<blockName> as block identifier data=<N> or
* data=<N>-<N2> as selecting matching states of identified blocks by ordered
* index of their block states (analog to metadata>
* state=<id:val>/<id2:val2>/... as selecting matching states (based on all
* states where given id=val values match)
*
* @return success or no
*/
public boolean processLine(String modid, String line, int linenum, Map<String, Integer> varMap) {
boolean success = true;
String tokens[] = line.split(","); // Split on the commas
this.basestates = new HashMap<DynmapBlockState, BitSet>();
this.badtokens = new ArrayList<String>();
this.modid = modid;
this.linenum = linenum;
this.filtered = false;
// Loop through and process id= tokens
for (String token : tokens) {
int idx = token.indexOf("="); // Find equals
if (idx < 0)
continue; // Skip token without equals
String fieldid = token.substring(0, idx); // Split off left of equals
String args = token.substring(idx + 1); // And rest of token after equals
// Just do IDs first (need block names to get to states
if (fieldid.equals("id")) {
if (!handleBlockName(args)) {
badtokens.add(token);
success = false;
}
}
}
// Loop through and process data= and state= tokens
for (String token : tokens) {
int idx = token.indexOf("="); // Find equals
if (idx < 0)
continue; // Skip token without equals
String fieldid = token.substring(0, idx); // Split off left of equals
String args = token.substring(idx + 1); // And rest of token after equals
// Check for data=
if (fieldid.equals("data")) {
if (!handleBlockData(args, varMap)) {
badtokens.add(token);
success = false;
}
}
// If state=
else if (fieldid.equals("state")) {
if (!handleBlockState(args)) {
badtokens.add(token);
success = false;
}
}
}
// If unfiltered, add all states for all blocks
if (!filtered) {
// Now loop through base states and add matching indexes
for (DynmapBlockState bs : basestates.keySet()) {
int cnt = bs.getStateCount();
BitSet bits = basestates.get(bs);
for (int idx = 0; idx < cnt; idx++) {
bits.set(bs.getState(idx).stateIndex);
}
}
}
// Log.info(String.format("processLine(%s)=%b, basestates=%s", line, success,
// basestates));
return success;
}
// Return matching results from last processLine call
public Map<DynmapBlockState, BitSet> getMatchingStates() {
return basestates;
}
// Return bad tokens from last processLine call
public List<String> getBadTokens() {
return badtokens;
}
private boolean handleBlockName(String blockname) {
char c = blockname.charAt(0);
if (Character.isLetter(c) || (c == '%') || (c == '&')) {
String orig = blockname;
if ((c == '%') || (c == '&')) {
blockname = blockname.substring(1);
}
if (blockname.indexOf(':') < 0) {
blockname = modid + ":" + blockname;
}
// Now find the base block state
DynmapBlockState bs = DynmapBlockState.getBaseStateByName(blockname);
// Bad if we failed
if (bs == null) {
Log.warning(String.format("id=%s on line %d does not match valid blockName", orig, linenum));
return false;
}
basestates.put(bs, new BitSet());
return true;
} else { // Numbers not support anymore
Log.warning(String.format("id=%s on line %d invalid format (numbers not supported anymore)", blockname,
linenum));
return false;
}
}
private boolean handleBlockData(String data, Map<String, Integer> varMap) {
try {
if (data.equals("*")) {
filtered = false;
} else {
int split = data.indexOf('-'); // See if range of data
int m0, m1;
if (split > 0) {
String start = data.substring(0, split);
String end = data.substring(split + 1);
m0 = getIntValue(varMap, start);
m1 = getIntValue(varMap, end);
} else {
m0 = m1 = getIntValue(varMap, data);
}
filtered = true;
// Now loop through base states and add matching indexes
for (DynmapBlockState bs : basestates.keySet()) {
int cnt = bs.getStateCount();
BitSet bits = basestates.get(bs);
for (int idx = m0; (idx <= m1) && (idx < cnt); idx++) {
bits.set(bs.getState(idx).stateIndex);
}
if ((m1 >= cnt) || (m0 >= cnt)) {
Log.warning(String.format("data=%s on line %d exceeds state count for %s", data, linenum,
bs.blockName));
}
}
}
return true;
} catch (NumberFormatException x) {
return false;
}
}
private boolean handleBlockState(String data) {
boolean success = true;
if (data.equals("*")) {
filtered = false;
} else {
String[] split = data.split("/"); // Split on pairs
String[] attribs = new String[split.length];
String[] vals = new String[split.length];
for (int i = 0; i < split.length; i++) {
String[] av = split[i].split(":");
if (av.length == 2) {
attribs[i] = av[0];
vals[i] = av[1];
} else {
success = false;
}
}
filtered = true;
// Now loop through base states and add matching indexes
if (success) {
for (DynmapBlockState bs : basestates.keySet()) {
int cnt = bs.getStateCount();
BitSet bits = basestates.get(bs);
for (int idx = 0; idx < cnt; idx++) {
DynmapBlockState s = bs.getState(idx);
boolean match = true;
for (int i = 0; match && (i < attribs.length); i++) {
if (!s.isStateMatch(attribs[i], vals[i])) {
match = false;
}
}
if (match) {
bits.set(idx); // Set matching state
}
}
}
}
}
if (!success) {
Log.warning(String.format("Bad block state %s for line %s", data, linenum));
}
return success;
}
private static Integer getIntValue(Map<String, Integer> vars, String val) throws NumberFormatException {
char c = val.charAt(0);
if (Character.isLetter(c) || (c == '%') || (c == '&')) {
int off = val.indexOf('+');
int offset = 0;
if (off > 0) {
offset = Integer.valueOf(val.substring(off + 1));
val = val.substring(0, off);
}
Integer v = vars.get(val);
if (v == null) {
if ((c == '%') || (c == '&')) { // block/item unique IDs
vars.put(val, 0);
v = 0;
} else {
throw new NumberFormatException("invalid ID - " + val);
}
}
if ((offset != 0) && (v.intValue() > 0))
v = v.intValue() + offset;
return v;
} else {
return Integer.valueOf(val);
}
}
}

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
// }
}
//
// }
}

View File

@ -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

View File

@ -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);

View File

@ -1,274 +0,0 @@
# Old v1.4 files
renderdata/ForgottenNature-models.txt
renderdata/ForgottenNature-texture.txt
renderdata/MineFactoryReloaded-models.txt
renderdata/MineFactoryReloaded-texture.txt
renderdata/PamHCApple-models.txt
renderdata/PamHCApple-texture.txt
renderdata/PamHCBean-models.txt
renderdata/PamHCBean-texture.txt
renderdata/PamHCBellpepper-models.txt
renderdata/PamHCBellpepper-texture.txt
renderdata/PamHCBlackberry-models.txt
renderdata/PamHCBlackberry-texture.txt
renderdata/PamHCBlueberry-models.txt
renderdata/PamHCBlueberry-texture.txt
renderdata/PamHCCandle-models.txt
renderdata/PamHCCandle-texture.txt
renderdata/PamHCCherry-models.txt
renderdata/PamHCCherry-texture.txt
renderdata/PamHCChilipepper-models.txt
renderdata/PamHCChilipepper-texture.txt
renderdata/PamHCCorn-models.txt
renderdata/PamHCCorn-texture.txt
renderdata/PamHCCotton-models.txt
renderdata/PamHCCotton-texture.txt
renderdata/PamHCCranberry-models.txt
renderdata/PamHCCranberry-texture.txt
renderdata/PamHCCucumber-models.txt
renderdata/PamHCCucumber-texture.txt
renderdata/PamHCGrape-models.txt
renderdata/PamHCGrape-texture.txt
renderdata/PamHCKiwi-models.txt
renderdata/PamHCKiwi-texture.txt
renderdata/PamHCLemon-models.txt
renderdata/PamHCLemon-texture.txt
renderdata/PamHCLettuce-models.txt
renderdata/PamHCLettuce-texture.txt
renderdata/PamHCOnion-models.txt
renderdata/PamHCOnion-texture.txt
renderdata/PamHCPeanut-models.txt
renderdata/PamHCPeanut-texture.txt
renderdata/PamHCRaspberry-models.txt
renderdata/PamHCRaspberry-texture.txt
renderdata/PamHCRice-models.txt
renderdata/PamHCRice-texture.txt
renderdata/PamHCSalt-texture.txt
renderdata/PamHCSpiceleaf-models.txt
renderdata/PamHCSpiceleaf-texture.txt
renderdata/PamHCStrawberry-models.txt
renderdata/PamHCStrawberry-texture.txt
renderdata/PamHCSunflower-models.txt
renderdata/PamHCSunflower-texture.txt
renderdata/PamHCTomato-models.txt
renderdata/PamHCTomato-texture.txt
renderdata/PamHCWhitemushroom-models.txt
renderdata/PamHCWhitemushroom-texture.txt
renderdata/PamWeeeFlowers-models.txt
renderdata/PamWeeeFlowers-texture.txt
renderdata/SoulShards-models.txt
renderdata/SoulShards-texture.txt
renderdata/Thaumcraft3-models.txt
renderdata/Thaumcraft3-texture.txt
renderdata/thermalexpansion-models.txt
renderdata/thermalexpansion-texture.txt
# Old 1.5 files
renderdata/archimedes-texture.txt
renderdata/bc-additionalpipes-texture.txt
renderdata/bc-models.txt
renderdata/bc-texture.txt
renderdata/BetterWorldsCoreBlocks-models.txt
renderdata/BetterWorldsCoreBlocks-texture.txt
renderdata/BetterWorldsCorners-models.txt
renderdata/BetterWorldsCorners-texture.txt
renderdata/BetterWorldsIntCorners-models.txt
renderdata/BetterWorldsIntCorners-texture.txt
renderdata/BetterWorldsPlantsAndFood-models.txt
renderdata/BetterWorldsPlantsAndFood-texture.txt
renderdata/BetterWorldsSlopes-models.txt
renderdata/BetterWorldsSlopes-texture.txt
renderdata/Biomes-O-Plenty-models.txt
renderdata/Biomes-O-Plenty-texture.txt
renderdata/ColoredBlocks-models.txt
renderdata/ColoredBlocks-texture.txt
renderdata/computercraft-texture.txt
renderdata/ee2-models.txt
renderdata/ee2-texture.txt
renderdata/enderstorage-texture.txt
renderdata/enterstorage-models.txt
renderdata/extrabees-texture.txt
renderdata/extrabiomesxl-bunyan-texture.txt
renderdata/extrabiomesxl-models.txt
renderdata/extrabiomesxl-texture.txt
renderdata/extrabiomesxl3-models.txt
renderdata/extrabiomesxl3-texture.txt
renderdata/FancyFences-models.txt
renderdata/FancyFences-texture.txt
renderdata/forestry-models.txt
renderdata/forestry-texture.txt
renderdata/gregslighting-texture.txt
renderdata/GregTech-models.txt
renderdata/GregTech-texture.txt
renderdata/ic2-advancedmachines-texture.txt
renderdata/ic2-advpowermanagement-texture.txt
renderdata/ic2-advsolarpanels-texture.txt
renderdata/ic2-chargingbench-texture.txt
renderdata/ic2-compactsolars-texture.txt
renderdata/ic2-models.txt
renderdata/ic2-nuclearcontrol-models.txt
renderdata/ic2-nuclearcontrol-texture.txt
renderdata/ic2-powerconverters-texture.txt
renderdata/ic2-texture.txt
renderdata/ironchest-models.txt
renderdata/ironchest-texture.txt
renderdata/lctrees-models.txt
renderdata/lctrees-texture.txt
renderdata/MetallurgyBase-texture.txt
renderdata/MetallurgyCore-texture.txt
renderdata/MetallurgyEnder-texture.txt
renderdata/MetallurgyFantasy-texture.txt
renderdata/MetallurgyNether-texture.txt
renderdata/MetallurgyPrecious-texture.txt
renderdata/MetallurgyUtility-texture.txt
renderdata/millenaire-models.txt
renderdata/millenaire-texture.txt
renderdata/mystcraft-texture.txt
renderdata/netherores-texture.txt
renderdata/ObsidiPlates-models.txt
renderdata/ObsidiPlates-texture.txt
renderdata/railcraft-models.txt
renderdata/railcraft-texture.txt
renderdata/railcraft6-models.txt
renderdata/railcraft6-texture.txt
renderdata/rp2-lighting-texture.txt
renderdata/rp2-logic-models.txt
renderdata/rp2-logic-texture.txt
renderdata/rp2-machine-models.txt
renderdata/rp2-machine-texture.txt
renderdata/rp2-models.txt
renderdata/rp2-texture.txt
renderdata/rp2-world-models.txt
renderdata/rp2-world-texture.txt
renderdata/superslopes-models.txt
renderdata/superslopes-texture.txt
renderdata/superslopes4-corners-models.txt
renderdata/superslopes4-corners-texture.txt
renderdata/superslopes4-intcorners-models.txt
renderdata/superslopes4-intcorners-texture.txt
renderdata/superslopes4-slopes-models.txt
renderdata/superslopes4-slopes-texture.txt
renderdata/superslopes4-slopres-texture.txt
renderdata/TFCraft-models.txt
renderdata/TFCraft-texture.txt
renderdata/Tropicraft-models.txt
renderdata/Tropicraft-texture.txt
renderdata/tubestuff-texture.txt
renderdata/TwilightForest-models.txt
renderdata/TwilightForest-texture.txt
renderdata/XyCraft-models.txt
renderdata/XyCraft-texture.txt
# Old 1.5.1 files
renderdata/1.5.1/ForgottenNature-models.txt
renderdata/1.5.1/ForgottenNature-texture.txt
renderdata/1.5.1/ThermalExpansion-models.txt
renderdata/1.5.1/ThermalExpansion-texture.txt
renderdata/1.5.1/PamHC/PamHCApple-models.txt
renderdata/1.5.1/PamHC/PamHCApple-texture.txt
renderdata/1.5.1/PamHC/PamHCBean-models.txt
renderdata/1.5.1/PamHC/PamHCBean-texture.txt
renderdata/1.5.1/PamHC/PamHCBellpepper-models.txt
renderdata/1.5.1/PamHC/PamHCBellpepper-texture.txt
renderdata/1.5.1/PamHC/PamHCBlackberry-models.txt
renderdata/1.5.1/PamHC/PamHCBlackberry-texture.txt
renderdata/1.5.1/PamHC/PamHCBlueberry-models.txt
renderdata/1.5.1/PamHC/PamHCBlueberry-texture.txt
renderdata/1.5.1/PamHC/PamHCCandle-models.txt
renderdata/1.5.1/PamHC/PamHCCandle-texture.txt
renderdata/1.5.1/PamHC/PamHCCherry-models.txt
renderdata/1.5.1/PamHC/PamHCCherry-texture.txt
renderdata/1.5.1/PamHC/PamHCChilipepper-models.txt
renderdata/1.5.1/PamHC/PamHCChilipepper-texture.txt
renderdata/1.5.1/PamHC/PamHCCorn-models.txt
renderdata/1.5.1/PamHC/PamHCCorn-texture.txt
renderdata/1.5.1/PamHC/PamHCCotton-models.txt
renderdata/1.5.1/PamHC/PamHCCotton-texture.txt
renderdata/1.5.1/PamHC/PamHCCranberry-models.txt
renderdata/1.5.1/PamHC/PamHCCranberry-texture.txt
renderdata/1.5.1/PamHC/PamHCCucumber-models.txt
renderdata/1.5.1/PamHC/PamHCCucumber-texture.txt
renderdata/1.5.1/PamHC/PamHCGrape-models.txt
renderdata/1.5.1/PamHC/PamHCGrape-texture.txt
renderdata/1.5.1/PamHC/PamHCKiwi-models.txt
renderdata/1.5.1/PamHC/PamHCKiwi-texture.txt
renderdata/1.5.1/PamHC/PamHCLemon-models.txt
renderdata/1.5.1/PamHC/PamHCLemon-texture.txt
renderdata/1.5.1/PamHC/PamHCLettuce-models.txt
renderdata/1.5.1/PamHC/PamHCLettuce-texture.txt
renderdata/1.5.1/PamHC/PamHCOnion-models.txt
renderdata/1.5.1/PamHC/PamHCOnion-texture.txt
renderdata/1.5.1/PamHC/PamHCPeanut-models.txt
renderdata/1.5.1/PamHC/PamHCPeanut-texture.txt
renderdata/1.5.1/PamHC/PamHCRaspberry-models.txt
renderdata/1.5.1/PamHC/PamHCRaspberry-texture.txt
renderdata/1.5.1/PamHC/PamHCRice-models.txt
renderdata/1.5.1/PamHC/PamHCRice-texture.txt
renderdata/1.5.1/PamHC/PamHCSalt-texture.txt
renderdata/1.5.1/PamHC/PamHCSpiceleaf-models.txt
renderdata/1.5.1/PamHC/PamHCSpiceleaf-texture.txt
renderdata/1.5.1/PamHC/PamHCStrawberry-models.txt
renderdata/1.5.1/PamHC/PamHCStrawberry-texture.txt
renderdata/1.5.1/PamHC/PamHCSunflower-models.txt
renderdata/1.5.1/PamHC/PamHCSunflower-texture.txt
renderdata/1.5.1/PamHC/PamHCTomato-models.txt
renderdata/1.5.1/PamHC/PamHCTomato-texture.txt
renderdata/1.5.1/PamHC/PamHCTurnip-models.txt
renderdata/1.5.1/PamHC/PamHCTurnip-texture.txt
renderdata/1.5.1/PamHC/PamHCWhitemushroom-models.txt
renderdata/1.5.1/PamHC/PamHCWhitemushroom-texture.txt
renderdata/1.5.1/PamHC/PamWeeeFlowers-models.txt
renderdata/1.5.1/PamHC/PamWeeeFlowers-texture.txt
renderdata/1.5.1/PamHC
renderdata/1.5.1
# Old 1.5.2 files
renderdata/1.5.2/Biomes-O-Plenty-0.5.8-models.txt
renderdata/1.5.2/Biomes-O-Plenty-0.5.8-texture.txt
renderdata/1.5.2/Biomes-O-Plenty-models.txt
renderdata/1.5.2/Biomes-O-Plenty-texture.txt
renderdata/1.5.2/Chisel-models.txt
renderdata/1.5.2/Chisel-texture.txt
renderdata/1.5.2/extrautilities-models.txt
renderdata/1.5.2/extrautilities-texture.txt
renderdata/1.5.2/immibisMicroblocks-models.txt
renderdata/1.5.2/immibisMicroblocks-texture.txt
renderdata/1.5.2/MineFactoryReloaded-models.txt
renderdata/1.5.2/MineFactoryReloaded-texture.txt
renderdata/1.5.2/Natura-models.txt
renderdata/1.5.2/Natura-texture.txt
renderdata/1.5.2/NumiRP-texture.txt
renderdata/1.5.2/SlabCraft-models.txt
renderdata/1.5.2/SlabCraft-texture.txt
renderdata/1.5.2/SoulShards-models.txt
renderdata/1.5.2/SoulShards-texture.txt
renderdata/1.5.2/StairCraft-models.txt
renderdata/1.5.2/StairCraft-texture.txt
renderdata/1.5.2/TConstruct-models.txt
renderdata/1.5.2/TConstruct-texture.txt
renderdata/1.5.2/Thaumcraft3-models.txt
renderdata/1.5.2/Thaumcraft3-texture.txt
renderdata/1.5.2/UndergroundBiomes-models.txt
renderdata/1.5.2/UndergroundBiomes-texture.txt
renderdata/1.5.2
# Old 1.6.2 files
renderdata/1.6.2/Artifice-models.txt
renderdata/1.6.2/Artifice-texture.txt
renderdata/1.6.2/Biomes-O-Plenty-0.5.8-models.txt
renderdata/1.6.2/Biomes-O-Plenty-0.5.8-texture.txt
renderdata/1.6.2/Biomes-O-Plenty-0.5.9-models.txt
renderdata/1.6.2/Biomes-O-Plenty-0.5.9-texture.txt
renderdata/1.6.2/Biomes-O-Plenty-models.txt
renderdata/1.6.2/Biomes-O-Plenty-texture.txt
renderdata/1.6.2/BuildCraft-models.txt
renderdata/1.6.2/BuildCraft-texture.txt
renderdata/1.6.2/coralmod-models.txt
renderdata/1.6.2/coralmod-texture.txt
renderdata/1.6.2/ExtrabiomesXL-models.txt
renderdata/1.6.2/ExtrabiomesXL-texture.txt
renderdata/1.6.2/railcraft8-models.txt
renderdata/1.6.2/railcraft8-texture.txt
renderdata/1.6.2
# Old 1.6.4 files
renderdata/1.6.4/GalacticraftCore-models.txt
renderdata/1.6.4/GalacticraftCore-texture.txt
renderdata/1.6.4/GalacticraftMars-models.txt
renderdata/1.6.4/GalacticraftMars-texture.txt
renderdata/1.6.4

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,13 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff"
}

View File

@ -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>

View File

@ -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 : '&timestamp=' + 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) {

Some files were not shown because too many files have changed in this diff Show More