Compare commits

..

734 Commits
v3.2.26 ... dev

Author SHA1 Message Date
ac9042bbe4 Various minor
New plugin updater and versioning
In game changelog
fix login teleporting
2017-08-09 15:05:13 +10:00
b280644661 Delete build 2017-08-09 15:01:16 +10:00
b924809c91 Fixes #1608 2017-08-03 23:13:04 +10:00
a913983d99 Add plot leave 2017-07-25 06:39:59 +10:00
3633576e03 Fix teleport for single plot worlds 2017-07-08 23:22:05 +10:00
73318f23a1 Fixes #1660 2017-07-08 21:56:15 +10:00
248751378b Fixes #1661 2017-07-08 21:50:47 +10:00
1918000668 Merge pull request #1645 from dordsor21/master
Lower TPS threshold please
2017-07-07 16:12:26 +10:00
9037b74720 Closes #1659 2017-07-07 16:11:46 +10:00
f6540bbfcb bypass owner check for download 2017-06-29 15:38:37 +10:00
507d0f19e4 Lower TPS threshold please 2017-06-24 16:11:52 +01:00
355e16fe92 Ignore searching top block for teleportation 2017-06-09 17:43:46 +10:00
2b1905889c Minor sponge fix 2017-05-16 13:20:28 +10:00
7ee67c8b41 Merge pull request #1599 from Gabscap/fix-min_height
Fix world.min_height setting
2017-05-03 14:58:16 +10:00
f8ab36b67c Fix world.min_height setting 2017-05-01 21:23:21 +02:00
b5ef5df20d * 2017-04-28 01:47:05 +10:00
509b1f1c3d Fixes #1593 2017-04-28 00:59:59 +10:00
bfe98f3285 Some claiming fixes 2017-04-20 14:12:40 +10:00
47915b8b86 Read sign on main thread 2017-04-20 01:09:52 +10:00
3c110bb125 Fixes #1585 2017-04-18 22:55:04 +10:00
a87fee1224 Merge pull request #1583 from manuelgu/patch-3
Added useSSL=false to JDBC connection URL
2017-04-17 22:28:20 +10:00
757b9c695f Fix compile 2017-04-17 19:11:55 +10:00
193948d4fd Fix claim 2017-04-17 11:56:10 +10:00
b616951e23 Added useSSL=false to JDBC connection URL
This is required according to MySQL 5.5.45+, 5.6.26+ and 5.7.6+.
2017-04-16 22:17:17 +02:00
37977f1da4 Check database before claiming plot 2017-04-15 12:40:23 +10:00
7eb7cd9b53 Ensure world loading occurs on the main thread 2017-04-11 01:49:01 +10:00
ddfcc5b077 Player login tweaks 2017-04-10 09:06:44 +10:00
9f6bf14649 Log when a plot is created/deleted 2017-04-09 17:10:23 +10:00
f99994737c Print error when failing to close database 2017-04-09 17:09:06 +10:00
6e0ade4f63 Some sponge fixes 2017-04-07 08:25:08 +10:00
c1a6c75ebe * 2017-04-04 08:07:54 +10:00
022372e9b7 Fixes #1534 + various
Auto world loading/unloading
Auto player teleporting on login
2017-04-04 07:59:36 +10:00
3f54ba23c2 Fix world delete 2017-04-01 04:36:45 +11:00
e8672df760 Add Gitter badge (#1565) 2017-03-27 12:03:33 -04:00
5d6f4c6668 Some plot area restructuring 2017-03-23 11:10:29 +11:00
a07ed4eafd * 2017-03-18 00:50:43 +11:00
5262ff665a Fix door break 2017-03-18 00:49:41 +11:00
1129a80329 Fixes #1510 2017-03-17 17:41:58 +11:00
a628c5927f Fixes #1560 2017-03-17 16:40:29 +11:00
478ad9670b Fixes #1476 2017-03-16 14:15:00 +11:00
8e3407505a Recover on database error
Might resolve #1476
2017-03-15 02:10:57 +11:00
e208d7f72a Fix mass purge 2017-03-15 01:28:02 +11:00
b0df79bb80 Break up purge task 2017-03-15 00:16:27 +11:00
411c75b219 Fixes #1556 Close #1555 2017-03-14 01:56:14 +11:00
491cc50440 Fixes #1528 2017-03-13 18:45:37 +11:00
e9723f5be1 Fixes #1532 2017-03-13 18:38:58 +11:00
a015039dad Fixes #1535
Set `misc_spawn_unowned`
2017-03-13 18:36:40 +11:00
a0640a1e66 Fixes #1536 2017-03-13 18:12:38 +11:00
0b6d2d3dd6 Fixes #1538 2017-03-13 18:07:48 +11:00
ad11ad3472 Fixes #1517 2017-03-13 18:02:05 +11:00
93717e670c Use InteractBlockEvent
For some reason sponge was calling the event twice, the second with a
relative location, which makes no sense. Switching to a different event
works.
2017-03-13 17:34:44 +11:00
38a33248e7 Send message on perm check 2017-03-13 09:04:40 +11:00
52496af9a1 Fix road interact on sponge 2017-03-13 07:16:16 +11:00
4d4950090d Fix 1.7 block placer 2017-03-10 07:07:50 +11:00
c8c144b6da Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2017-03-08 16:51:29 +11:00
e94adb04ea Add maven repo
closes #1394
2017-03-08 16:51:01 +11:00
395c1c743f Merge pull request #1537 from HexagonMC/master
Fix plot teleport.
2017-03-06 15:40:28 +11:00
b1fb01303d Fix plot teleport.
Fixes https://github.com/IntellectualSites/PlotSquared/issues/1302
2017-02-20 20:29:43 +01:00
aa7b770c03 tweak highest block check 2017-01-31 16:45:02 +11:00
e7990a06e2 Check player name for invalid character first 2017-01-30 19:42:16 +11:00
88f5e5b0bc Sort player names 2017-01-15 22:51:54 +11:00
47db330764 Fix title global flag 2017-01-13 08:05:13 +11:00
35ebc8c830 Permission check fix 2017-01-13 07:22:28 +11:00
686a6c499f Fixes #1502 2017-01-11 07:53:53 +11:00
cb6d839214 Possible fix for #1476
Changes database load to prefer the latest entry over older ones.

Some previous changes may fix connections dropping, which resulted in
(incorrect) fixes being attempted by the plugin.
2017-01-11 07:21:36 +11:00
6af96f43d4 Optimize schematic paste 2016-12-31 17:23:46 +11:00
e3eccfd476 Fix debugpaste 2016-12-31 17:23:38 +11:00
15d4b6d34b Bump spigot version 2016-12-29 07:23:51 +11:00
c3e2421d51 Merge pull request #1492 from c7w/master
Update s_chinese.yml
2016-12-25 17:32:36 +11:00
c7w
f7793f027c Update s_chinese.yml 2016-12-25 14:30:32 +08:00
6ec96870c0 Fix SO 2016-12-23 15:33:19 +11:00
a843203ca3 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	Core/src/main/java/com/intellectualcrafters/plot/object/Plot.java
2016-12-15 17:42:51 +11:00
3240fc9559 Exit plot on unclaim
Fixes #1471
2016-12-15 17:37:26 +11:00
5fd1486cec Merge pull request #1478 from EvilOlaf/patch-2
Update ISSUE_TEMPLATE.md
2016-12-13 01:44:37 +11:00
d648148f51 Update ISSUE_TEMPLATE.md 2016-12-12 15:42:00 +01:00
d554dab8c8 Fix potential NPE with claiming 2016-12-10 14:33:48 -05:00
9ad45750ee Unclaiming a plot should call plotExit() 2016-12-09 20:58:05 -05:00
a554ae5633 Potential fix for commands 2016-12-09 16:58:32 -05:00
7b1c4a5042 Check border when claiming a plot
Also fixes #1467
2016-12-10 01:09:07 +11:00
9fc464e896 Shorter border teleportation 2016-12-10 00:44:42 +11:00
bec11b244e Use the correct plot id 2016-12-10 00:26:40 +11:00
dc94418b51 Only expand border to current plot. 2016-12-09 23:52:48 +11:00
72ab10c079 remove debug 2016-12-03 23:08:10 +11:00
f50d32f06b * 2016-12-02 17:17:16 +11:00
6cc744a2e6 Fixes #1444 2016-12-02 17:16:19 +11:00
e40dc37f89 Fix versioning messup. 2016-12-01 21:56:19 -05:00
7e34d9e20a Fix title logic 2016-11-30 21:26:52 +11:00
c891abce09 Allow added players to use frost walker
Properly fixes #1438
2016-11-30 20:46:48 +11:00
2b561f2efa Rename to ice-form 2016-11-30 19:06:03 +11:00
dea0a452df Add fading 1.11 titles 2016-11-30 16:28:50 +11:00
81418b07a8 Fixes #1438 (unless other things call this event) 2016-11-30 16:15:20 +11:00
a3c1ad3ec8 Fixes #1449 2016-11-30 16:10:08 +11:00
7c6c19ba63 Fixes #740 2016-11-30 16:07:16 +11:00
2e23ae0811 Fixes #1243 2016-11-30 16:00:47 +11:00
28e7f5bc08 Fixes #1349
Non standard plot managers/areas not supported
2016-11-30 15:57:24 +11:00
7a1417dc56 Fixes #1415 2016-11-30 15:45:28 +11:00
e7fa9e01be Fixes #1419 2016-11-30 15:43:23 +11:00
93414d54c1 Fixes #1453 2016-11-30 15:41:08 +11:00
5642fd3899 Fixes #1359
plots.chat.color
and
PLOT_CHAT_SPY_FORMAT
2016-11-30 15:36:13 +11:00
f3d950f6e1 Fix flame enchant damaging entities 2016-11-30 15:03:48 +11:00
95f8aaa2fe this could be here? 2016-11-30 13:10:36 +11:00
878010255c Java 9 2016-11-28 18:02:03 +11:00
8edc357d01 Fixed #1448 2016-11-27 01:26:06 -05:00
588639d9c2 3.5.1 Start 2016-11-27 01:08:35 -05:00
ff401b65c4 3.5.0 Release 2016-11-26 18:02:39 -05:00
11913bfbe5 Fix compile issue 2016-11-26 17:53:44 -05:00
62b353f82d Various Sponge changes
- many improvements
- inventory utilities broke when updating to Sponge API 6.0.0
2016-11-26 16:49:13 -05:00
8d442f58d4 Fixes #1445 2016-11-26 12:05:08 -05:00
5cbd2f44bd Update Sponge Gradle 2016-11-26 11:55:59 -05:00
dc673f9715 Fixed #1440 , Fixed #1446 2016-11-26 11:55:38 -05:00
deb5441bcf *Fix compile error 2016-11-24 11:05:28 +11:00
8ebf71c87f DB fix 2016-11-24 10:19:00 +11:00
9fd53af483 Add world argument 2016-11-23 15:47:18 +11:00
fb729df59e Setting to sort plots by area 2016-11-23 15:36:25 +11:00
ce6e1be13e Fix maven dependencies (#1439)
* Fixes

* Fix wrong version
2016-11-21 09:59:11 -05:00
e126054053 Fixes #1429 Removes duplicate aliases. 2016-11-20 22:29:14 -05:00
77281017d4 Fixes #1428 , Fixes #1431 2016-11-20 22:24:27 -05:00
e0208aa369 Fix plot help category pagination 2016-11-18 10:49:03 +11:00
fdc42a3d5c Seems the new spigot 1.11 sqlite driver has issues parsing timestamps, no idea why. 2016-11-18 09:08:41 +11:00
3070557a3a Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-11-13 22:18:11 +11:00
2ec0b55482 Fix database lock error 2016-11-13 22:17:17 +11:00
10dd9b6371 Merge pull request #1424 from c7w/master
translation
2016-11-13 06:41:25 +11:00
c7w
1ac0a7dad0 translation
translation of chinese
2016-11-12 12:52:43 +08:00
f8b1fcffa1 Fix worldedit mask area 2016-11-12 00:14:12 +11:00
17762f5ae7 Tweak delete message 2016-11-09 00:13:46 +11:00
1d7cdde84a Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-11-02 04:28:11 +11:00
c950b0021f Notify inbox permission 2016-11-02 04:27:52 +11:00
e4bc2b30b1 Update ISSUE_TEMPLATE.md (#1409) 2016-10-28 10:15:38 -04:00
e0c4c944bb Merge remote-tracking branch 'origin/master' 2016-10-26 23:01:01 -04:00
dd09ef18e6 Add missing gradle batch
Signed-off-by: MattBDev <mattbdev@outlook.com>
2016-10-26 23:00:43 -04:00
68011f43cd Fixes #1390 2016-10-21 03:51:27 +11:00
93c4854454 Add misc-interact flag 2016-10-18 05:03:14 +11:00
e594227d95 Fix some height issues 2016-10-14 16:56:28 +11:00
d6be5703ae Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-10-14 15:14:35 +11:00
c97544d083 Minor fixes 2016-10-14 15:14:08 +11:00
a05fd2dd11 Fix #1386
Signed-off-by: MattBDev <mattbdev@outlook.com>
2016-10-10 00:18:35 -04:00
5978c9c3c0 Fix center 2016-10-03 00:56:27 +11:00
5d3e096501 *Fix the toggle 2016-10-03 00:56:26 +11:00
39e99c0593 Merge pull request #1381 from filoghost/patch-1
Fix permission checks being ignored
2016-10-02 14:08:22 +11:00
cd33aaa1b6 Fix permission checks being ignored 2016-10-01 21:35:57 +02:00
0244c0241c Trim deletes expired plots 2016-10-01 20:17:50 +10:00
5ed2190cb3 Fixes #1369 2016-09-30 23:32:49 +10:00
c533f0bae9 Fix area removal 2016-09-30 17:05:18 +10:00
cd2b6c8ccc Fixes #1379 2016-09-30 17:04:06 +10:00
6f2c7de0ff Minor fix to conversion 2016-09-30 16:46:10 +10:00
62373c0737 * 2016-09-30 16:15:15 +10:00
499120963a Streamline PlotMe conversion
Use reflection to disable PlotMe and forward DefaultGenerator to
PlotSquared
Fix border material copying from plotme config
You no longer need to delete the PlotMe jar for conversion
Fix some outdated messages
2016-09-30 16:14:35 +10:00
f1d581a8d8 Fixes #1377 2016-09-30 15:29:50 +10:00
6074fc8033 Nukkit generator fixes 2016-09-30 14:26:20 +10:00
e4d7270c28 Fix some merged plot events 2016-09-30 03:30:34 +10:00
b6df07f723 Add snow-form flag 2016-09-27 01:38:59 +10:00
177b33154f Multiple
Fixes #1362
Fixes border id for PlotMe converter
2016-09-27 00:56:39 +10:00
6bf2fbcfcf Command tweaks 2016-09-26 18:33:27 +10:00
12f8861d07 Various
externalize strings
plotme conversion fixes
2016-09-26 18:31:08 +10:00
c99e23bd3c Fixes #1367 2016-09-25 18:48:38 +10:00
1b6d08b3fe Fixes #1365 2016-09-25 18:43:53 +10:00
3b4490c1c6 Fixes #1366 2016-09-25 18:42:05 +10:00
04c011164a Add near cmd 2016-09-25 18:06:20 +10:00
86b776f742 Nukkit perms 2016-09-25 16:49:51 +10:00
61022b717a Fixes #1360 2016-09-21 13:42:59 +10:00
9e5af7a642 Possible fix for redstone in merged plots 2016-09-20 23:49:22 +10:00
364b4347d1 Fix area id parsing 2016-09-19 14:18:47 +10:00
d89274ce09 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java
2016-09-17 16:03:57 +10:00
264114332b Let generator be up to the implementation 2016-09-17 16:02:05 +10:00
a4363bdb27 Fix #1355
There is the possibility this will cause issues with sponge

Signed-off-by: MattBDev <mattbdev@outlook.com>
2016-09-14 19:27:30 -04:00
8e7e5dcb25 Cleanup
Signed-off-by: MattBDev <mattbdev@outlook.com>
2016-09-14 12:16:22 -04:00
56227a6d7d Fixes #1351 2016-09-14 10:21:14 +10:00
63259ec269 Merge pull request #1352 from MisterErwin/master
A (possible) fix to #1351
2016-09-14 10:17:11 +10:00
0286a7b046 Fixes #1131 2016-09-14 10:12:53 +10:00
b6dac54677 Code cleaning and Gradle Update
Updated gradle wrapper to 3.0
Updated Gradle files for Nukkit
Added/cleaned minor Nukkit code
Removed duplicate TitleManagement code

Signed-off-by: MattBDev <mattbdev@outlook.com>
2016-09-13 18:10:01 -04:00
bf1d487508 A (possible) fix to #1351 2016-09-12 17:05:13 +02:00
a95b68b73c Add villager-interact flag 2016-09-09 15:17:37 +10:00
85ff8bf639 Minor tweaks 2016-09-07 00:28:01 +10:00
0557671b80 Recover from third party generator error 2016-09-04 14:22:01 +10:00
d75ab130da Sponge fixes 2016-09-02 15:58:24 +10:00
6a12a6ba64 print chat to console
Fixes #1339
2016-09-02 15:47:19 +10:00
22901bf9f2 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-09-01 16:57:52 +10:00
07ee19b4bb Fixes #1337 2016-08-31 19:09:17 +10:00
27c21b9ab6 Fix #1321 2016-08-30 21:50:52 -04:00
da7a12bc00 Fixes #1234 2016-08-29 16:21:14 +10:00
3b73b2e9d8 Fix grant check 2016-08-29 15:33:26 +10:00
970c80cb15 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-08-29 15:01:27 +10:00
dd665ed9ce Fence rotation 2016-08-29 15:01:19 +10:00
572da7d436 Merge pull request #1332 from manuelgu/patch-2
Might resolve #1331
2016-08-29 14:41:48 +10:00
ab05b026e9 Merge pull request #1335 from Herocraft/fix/vault-repo
Switch Vault repository to the real one
2016-08-29 12:19:48 +10:00
2fcb59f8cf Switch Vault repository to the real one 2016-08-28 18:26:11 -07:00
20250bc989 Might resolve #1331
Wasn't able to reproduce the issue
2016-08-28 20:14:58 +02:00
5e4798165b Merge pull request #1330 from MinelinkNetwork/fix-pom
Fix Spigot artifact in POM
2016-08-28 18:26:57 +10:00
7fc3fb097e Fix Spigot artifact in POM
Use the correct groupId, artifactId and version of Spigot dependency
installed by BuildTools
2016-08-28 01:13:21 -07:00
3a08e5c091 Merge pull request #1326 from SupremeMortal/SupremeMortal-patch-1
Update Non-existent Repo
2016-08-28 00:52:04 +10:00
50770a78d7 Fixed mistake 2016-08-27 14:09:03 +01:00
1266eed86a Add Replacement Repo For Vault 2016-08-27 14:08:35 +01:00
c0996299b4 Remove non-existent Repo
"nexus.theyeticave.net" does not exist anymore.
2016-08-27 14:03:41 +01:00
90d48b2cd0 Fixes #1289 2016-08-26 13:54:22 +10:00
a95d18499e Fixes #1285 2016-08-26 13:19:42 +10:00
61d00e51ef Fixes #1303 2016-08-26 03:02:50 +10:00
b5349e16f0 Fixes #1305
Just teleports the player further back
Combine move/tp since tp extends move
2016-08-26 02:31:50 +10:00
a801127036 Merge pull request #1301 from MisterErwin/master
Calling events when players are removed from plots & correct calling of Member & Trusted events
2016-08-26 02:02:40 +10:00
2806f8b20c Fixes #1307 2016-08-26 01:36:35 +10:00
7d11147836 Add Lazzy "Offline -> Offline Lowercase" conversion 2016-08-20 21:40:54 +10:00
74a6df1fa7 Update README.md 2016-08-20 00:26:53 -04:00
bc0c0abe7e Fix NPE 2016-08-19 12:16:13 +10:00
56907e4580 Version Bump
3.4.6-SNAPSHOT
2016-08-18 10:38:06 -04:00
005e13a216 Maybe #1239 2016-08-17 18:30:58 +10:00
3558105789 Fix default flags NPE 2016-08-17 15:08:01 +10:00
f651607d2f Might work? 2016-08-17 12:22:45 +10:00
6b95e57d9e Merge pull request #1313 from MinelinkNetwork/blocked-cmds
Only show blocked-cmds message when event is cancelled
2016-08-17 12:13:27 +10:00
98d0819383 Only show blocked-cmds message when event is cancelled 2016-08-16 19:09:02 -07:00
30da060f83 Potential fix for schematic placement on clear 2016-08-16 15:53:26 +10:00
e4408d56ec *And this 2016-08-16 14:32:31 +10:00
f07ac646f3 Possible fix for greeting spam 2016-08-15 09:31:03 +10:00
ef3380dc0a Merge remote-tracking branch 'origin/master' 2016-08-12 15:04:18 -04:00
749ab83e5d Move permission check out of loop
See #1307
2016-08-12 15:04:11 -04:00
daea9cf60d Allow teleportation for console 2016-08-10 12:33:18 +10:00
2f74368879 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-08-09 12:45:45 -04:00
63d4476d97 Fix #1181 2016-08-09 12:40:38 -04:00
db69da5b07 *Wrong runnable 2016-08-09 08:52:31 +10:00
634802ef98 Got rid of that auto-optimize-imports option 2016-08-08 23:20:31 +02:00
37e4a652dd Now calling the respective events when a user is removed from a plot.
And switched the event calling of adding Helpers and Trusted players. (Correct me if that was wrong)
2016-08-08 22:45:08 +02:00
d22f7b8781 Merge remote-tracking branch 'origin/master' 2016-08-08 14:03:17 -04:00
112da17614 Squashed commit of the following:
commit 91c78407cd
Author: Jesse Boyd <jessepaleg@gmail.com>
Date:   Sun Aug 7 11:29:59 2016 +1000

    Use a queue for expiry

commit 395d6364be
Author: Jesse Boyd <jessepaleg@gmail.com>
Date:   Sun Aug 7 04:43:41 2016 +1000

    Cache on fail as well

commit facd43700d
Author: Jesse Boyd <jessepaleg@gmail.com>
Date:   Sun Aug 7 04:00:50 2016 +1000

    Cache entity count every second

commit 1ae694ff5b
Author: Jesse Boyd <jessepaleg@gmail.com>
Date:   Sun Aug 7 03:52:37 2016 +1000

    Tweak entity counting

commit c99dd1e74a
Author: Jesse Boyd <jessepaleg@gmail.com>
Date:   Sat Aug 6 00:10:11 2016 +1000

    Needs sponge builds

commit f408ac82be
Author: Alexander Söderberg <Sauilitired@users.noreply.github.com>
Date:   Fri Aug 5 12:13:39 2016 +0200

    Update README.md

commit 9b95990ba6
Author: Alexander Söderberg <Sauilitired@users.noreply.github.com>
Date:   Thu Aug 4 16:50:37 2016 +0200

    Update this here as well
2016-08-08 14:02:25 -04:00
91c78407cd Use a queue for expiry 2016-08-07 11:29:59 +10:00
395d6364be Cache on fail as well 2016-08-07 04:43:41 +10:00
facd43700d Cache entity count every second 2016-08-07 04:00:50 +10:00
1ae694ff5b Tweak entity counting 2016-08-07 03:52:37 +10:00
c99dd1e74a Needs sponge builds 2016-08-06 00:10:11 +10:00
f408ac82be Update README.md 2016-08-05 12:13:39 +02:00
9b95990ba6 Update this here as well 2016-08-04 16:50:37 +02:00
77fb329c9e Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-07-31 21:26:18 -04:00
a13b9fb31b flag tix 2016-08-01 11:20:06 +10:00
ea3306d070 Fix #1034 2016-07-31 20:17:35 -04:00
bcbcd6d916 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-07-31 18:14:12 +10:00
415c6fb0d4 Fixes #1283 2016-07-31 18:14:06 +10:00
e801c6d7e8 Merge branch '3.4.5' 2016-07-31 00:16:37 -04:00
409456e895 Minor sponge fix 2016-07-31 09:16:58 +10:00
e8f4eae6f7 Merge remote-tracking branch 'origin/3.4.5' into 3.4.5
# Conflicts:
#	Sponge/build.gradle
#	Sponge/src/main/java/com/plotsquared/sponge/util/SpongeSetupUtils.java
2016-07-29 21:45:34 -04:00
c8419f4a4a Added more Java 8 warnings 2016-07-29 21:40:23 -04:00
09994724db Fix #1277 2016-07-29 21:40:02 -04:00
610e204d12 Fix #1281 , Fix #1282 , and Sponge gradle 2016-07-29 12:47:42 -04:00
1f341e6ba9 Merge remote-tracking branch 'origin/master' into 3.4.5
# Conflicts:
#	Sponge/src/main/java/com/plotsquared/sponge/SpongeMain.java
#	Sponge/src/main/java/com/plotsquared/sponge/generator/SpongeAugmentedGenerator.java
#	Sponge/src/main/java/com/plotsquared/sponge/util/SpongeSetupUtils.java
#	Sponge/src/main/java/com/plotsquared/sponge/util/SpongeUtil.java
#	Sponge/src/main/java/com/plotsquared/sponge/util/block/GenChunk.java
#	build.gradle
2016-07-29 12:25:11 -04:00
ffddf5c187 Fix sponge generator cast 2016-07-29 12:12:28 +10:00
b5ec6232f9 Sponge Fixes and minor changes. 2016-07-25 22:25:15 -04:00
34c2da55ca Change Sponge method behavior 2016-07-25 22:25:15 -04:00
33ec80c2cb Fix Sponge generation casting 2016-07-25 22:25:15 -04:00
48064da1ee Fixed deny-teleport flag 2016-07-25 22:25:15 -04:00
adc021109f Added Polar Bear where missing 2016-07-25 22:25:15 -04:00
d23d8c2fd8 *should use this cause instead 2016-07-25 22:25:15 -04:00
3498f309e8 Minor sponge fixes 2016-07-25 22:24:31 -04:00
0b5177f192 Minor uuid cache changes 2016-07-25 22:23:49 -04:00
07dc6a46fb Remove metrics depend 2016-07-25 22:23:19 -04:00
0b19cc7d9d Possible fix + add guest-gamemode flag 2016-07-25 22:23:19 -04:00
4e019ab796 UUID cache changes 2016-07-25 22:23:19 -04:00
b2fdcad317 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared into 3.4.5
# Conflicts:
#	Sponge/src/main/java/com/plotsquared/sponge/util/SpongeUtil.java
#	Sponge/src/main/java/com/plotsquared/sponge/util/block/GenChunk.java
2016-07-25 22:08:54 -04:00
80ea3e9ce7 Sponge Fixes and minor changes. 2016-07-25 20:00:59 -04:00
5f8c77a6cd Change Sponge method behavior 2016-07-25 18:43:11 -04:00
290e5c68dc Fix Sponge generation casting 2016-07-25 18:42:31 -04:00
5d92701100 Fixed deny-teleport flag 2016-07-25 18:04:17 -04:00
1a86d5fb9e Added Polar Bear where missing 2016-07-25 01:19:29 -04:00
30d18c917d *should use this cause instead 2016-07-25 09:54:35 +10:00
b91eab2f0c Minor sponge fixes 2016-07-25 09:47:49 +10:00
770b9be160 Minor uuid cache changes 2016-07-25 09:23:20 +10:00
14b2b11bf3 Remove metrics depend 2016-07-25 08:09:57 +10:00
975a5765c1 Possible fix + add guest-gamemode flag 2016-07-25 08:02:17 +10:00
2b9c2959cf Merge branch '3.4.5' of https://github.com/IntellectualSites/PlotSquared into 3.5.0 2016-07-24 17:45:34 -04:00
07977ac2ce UUID cache changes 2016-07-25 07:44:47 +10:00
9e5ac80435 Merge remote-tracking branch 'origin/3.4.5' into 3.4.5 2016-07-24 17:42:21 -04:00
dda6849412 Fix sponge compile 2016-07-24 17:42:03 -04:00
85d6e42462 Merge branch '3.4.5' of https://github.com/IntellectualSites/PlotSquared into 3.5.0 2016-07-24 17:27:41 -04:00
b1ee223b0a Merge pull request #1271 from manuelgu/patch-1
Make debug output useful
2016-07-24 07:51:45 +02:00
98e865cdf0 Make debug output useful 2016-07-23 12:50:39 +02:00
8b084839fd Fix #1261 2016-07-19 10:22:50 -04:00
c1d4c481fb Fix #1244 2016-07-17 23:20:31 -04:00
269e409e3e Version Bump 2016-07-17 23:19:37 -04:00
8538170cba Metrics 2016-07-16 22:51:49 -04:00
76bce7c0ef Catch CommandException 2016-07-14 20:29:11 +10:00
ba568a3f60 Recover from invalid flag value 2016-07-14 00:28:46 +10:00
a43430b722 Fix NPE for null arg 2016-07-13 00:14:26 +10:00
e2c57cea52 . 2016-07-12 23:56:59 +10:00
ca776b2912 Fixes #1226 2016-07-12 22:12:14 +10:00
e859a7f56c Change to interact perm, not build 2016-07-11 20:27:25 +10:00
ad2db9b836 Merge pull request #1245 from manuelgu/fix/CentreCenterName
Add additional alias for /p middle
2016-07-10 22:58:54 +10:00
279084b043 Add additional alias for /p middle
http://grammarist.com/spelling/center-centre/
2016-07-09 09:18:55 +02:00
8b0e59209c Remove getServerName() 2016-07-05 23:43:08 -04:00
ca8b82dcbe Version Bump 2016-07-05 23:39:38 -04:00
cf5d2a5e86 Entity Fix and Gradle changes 2016-07-01 17:13:49 -04:00
b9ad75ad84 Add teleport flag 2016-06-29 21:22:55 +10:00
185352d3cf Fixes #1229 2016-06-29 15:23:10 +10:00
f4fe762135 * 2016-06-28 20:21:50 +10:00
06682b18a5 Fix compile
Recover on unknown command error
Fixes #1224
Close #1213 (fixed elsewhere)
Fixes #1212
2016-06-28 19:55:51 +10:00
f8e97f14d6 Fix end crystal spawn cap 2016-06-28 02:03:23 +10:00
a579df00db Merge remote-tracking branch 'origin/master' 2016-06-27 10:14:28 -04:00
29a0b68dcb Fix currently online for seen info. 2016-06-27 23:59:38 +10:00
d2581bf38b Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-06-27 09:58:17 -04:00
817a5bc16e Various
Fix compatibility with bukkit 1.5
Recover on failed fancy message initialization
Fix /2 remove *
2016-06-27 18:38:14 +10:00
047f9a75b9 Fix #1222 2016-06-27 17:45:19 +10:00
96d0bb0e5e bump pom version 2016-06-26 17:08:54 +10:00
7da0b9877f Fixes #1221 (the NPE at least) 2016-06-26 17:07:46 +10:00
f20ef15774 Revert creature spawn message + change expire to seen 2016-06-26 04:30:12 +10:00
3a973342ae Merge remote-tracking branch 'origin/master' 2016-06-24 10:59:18 -04:00
6e25aab51f Cleanup some docs. 2016-06-24 10:56:38 -04:00
a49492aae3 Fix roadregen 2016-06-24 16:16:22 +10:00
dbe965e901 init script engine on get 2016-06-24 15:41:34 +10:00
2c82d1106a Fixed kick message 2016-06-23 23:19:02 -04:00
5b9dc59abf Updates to docs, code style tweaks, and some code optimizations 2016-06-23 20:12:17 -04:00
b587b430b8 #1211 2016-06-24 05:30:26 +10:00
8fd2599686 Fixes #1211 2016-06-24 02:20:21 +10:00
56000d60e7 Just in case 2016-06-23 13:14:29 +10:00
1643399fc6 Alternatives for setowner none if the username is taken 2016-06-23 13:11:26 +10:00
532fd09800 Merge remote-tracking branch 'origin/master' 2016-06-22 23:10:15 -04:00
e6387419f7 Potential fix for plot biome (untested) 2016-06-23 13:09:56 +10:00
30d49880b6 Fix #1208 NPE 2016-06-22 16:31:04 -04:00
16d191db2c Fixes /plot kick * 2016-06-23 04:08:06 +10:00
7dc7714261 Update Gradle to 2.14 2016-06-22 12:31:25 -04:00
9e1f6d8748 Closes #1209 2016-06-22 13:33:32 +10:00
7fb2631421 Cast to string if necessary 2016-06-21 14:23:04 +10:00
718831e8e0 * 2016-06-21 14:10:20 +10:00
df4585a847 Check args for grant 2016-06-21 13:38:08 +10:00
88d8339cfd fix other NPE 2016-06-21 13:32:28 +10:00
e08db3d12b Check teleportation on command location prefix 2016-06-21 03:02:41 +10:00
2ff4e07919 Setup border on world creation 2016-06-21 01:13:09 +10:00
f6fec56677 Potential fix for terrain 3 worlds. 2016-06-21 00:29:39 +10:00
3fabfa10d7 Add liquid-flow flag 2016-06-20 22:48:04 +10:00
a2ca9a52ea Merge pull request #1205 from manuelgu/fix/deadlink
Remove dead link
2016-06-20 18:52:35 +10:00
e5e3600206 Why were these restricted to players? 2016-06-20 18:52:00 +10:00
7ad50b6314 Remove dead link 2016-06-20 10:49:40 +02:00
01d508edf4 Fix remove * 2016-06-20 15:08:56 +10:00
9fa28e1179 * 2016-06-20 01:50:43 +10:00
c3dd28caeb Fix clear done flag requirements 2016-06-20 01:49:35 +10:00
0888940307 bump version 2016-06-20 01:37:27 +10:00
ce7468e63a Fix economy NPE 2016-06-20 00:52:05 +10:00
f5e7d08ace Allow duplicates after 5s 2016-06-19 16:14:13 +10:00
3ce225c044 Bump version 2016-06-19 15:51:46 +10:00
c2f10a7065 Update desc for debugpaste 2016-06-19 13:44:14 +10:00
8512adf9d6 Fix for augmented 2016-06-19 13:01:30 +10:00
b2c885e8d1 Merge pull request #1197 from manuelgu/patch-1
Fix #1196
2016-06-19 00:15:20 +02:00
5eabf863d6 Fix #1196 2016-06-19 00:11:21 +02:00
cff30a1db4 Fix scripting initialization 2016-06-18 16:29:51 +10:00
ab51d27e49 Remove pointless thread dump 2016-06-18 15:01:42 +10:00
6375922808 I can't count + fix variable scope 2016-06-18 13:54:35 +10:00
29ce4af350 Fixes #987 and #299 (untested)
Example usage:
claim: 50*{arg}
2016-06-18 13:43:34 +10:00
3ced832b80 Fix biome stripes (whoops) 2016-06-18 13:15:50 +10:00
91c742c141 Fixes #590 2016-06-18 13:13:36 +10:00
232091454a Fix augmented 2016-06-18 12:44:56 +10:00
600d060b6e Fix sponge compile issue 2016-06-17 22:05:06 +10:00
081081b36e Fixes #1063 2016-06-17 15:42:23 +10:00
4319300b34 Fixes #1126 2016-06-17 13:46:13 +10:00
b2b90a8d17 Fixes #1064 2016-06-17 13:33:47 +10:00
480453b716 Various
Fixes #1177
Additional check for left click with milk on adult entity
Add setting for enabling persistent meta
Only set fly persistent meta if it differs from the current gamemode fly
mode.
2016-06-16 20:16:48 +10:00
28ad14500a Fixes #1172 2016-06-16 17:59:39 +10:00
2bbfec1a32 Fix load / flush queue before sending message 2016-06-16 17:31:02 +10:00
b2997b7c7b Don't send duplicate messages 2016-06-16 10:31:33 +10:00
472aadcd01 Add suggestion for flags when invalid flag name was given :] 2016-06-16 02:30:16 +02:00
5b103d49c0 Fixes #1171 2016-06-16 02:08:01 +02:00
ae5e15e434 Fix invalid record type error 2016-06-13 15:05:38 -04:00
341967cbfc Reclassify armor stand as vehicle 2016-06-13 15:35:33 +10:00
b238bdbd21 Fix armor stand / hangings being considered vehicles 2016-06-13 15:32:13 +10:00
4f0ede646e Chat / Merge blocks placer / generator 2016-06-13 14:47:50 +10:00
506455ae40 Remove debug 2016-06-12 15:33:56 +10:00
15c7957d0e Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-06-12 15:27:23 +10:00
6165469e76 Fix scripting 2016-06-12 15:26:58 +10:00
a7087f314f Merge remote-tracking branch 'origin/master' 2016-06-11 19:25:27 -04:00
0cfef63376 Fix backwards compatibility 2016-06-11 19:25:13 -04:00
bfd9b53555 Update pom 2016-06-11 11:58:11 +10:00
5bdb2263dc CheckStyle code tweaks 2016-06-10 14:04:55 -04:00
76bcb76905 Merge remote-tracking branch 'origin/master' 2016-06-10 13:31:41 -04:00
93deebf4ca 1.10 fixes 2016-06-10 13:31:28 -04:00
482f4d6815 Modify Setting and Storage class names. 2016-06-10 13:00:34 -04:00
0d47e4599f Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-06-09 18:06:08 +10:00
f41c7dc1f6 Fix NPE 2016-06-09 18:06:00 +10:00
8fe381d098 Fix SpongeCommand 2016-06-08 19:06:07 -04:00
12c01760a6 Tweaks and small memory improvement. 2016-06-06 01:43:06 -04:00
880e084006 Register expiry tasks 2016-06-06 12:47:54 +10:00
f1f6b2781e Fix INSTABREAK flag 2016-06-06 06:34:05 +10:00
237a0d8b6b Always cache * uuid 2016-06-05 20:11:02 +10:00
a1c722aa9e Fix player location/current plot 2016-06-05 20:03:05 +10:00
960ad50070 Use DBFunc instead of dbManager 2016-06-05 19:54:33 +10:00
7d44850bb0 Mask getBlock 2016-06-05 19:46:52 +10:00
7427d83ae2 final primitives are final 2016-06-05 19:39:51 +10:00
48cf381ed6 * 2016-06-05 18:57:11 +10:00
0114dd7558 Fix convert 2016-06-05 18:42:34 +10:00
48382e0c4e Remove null version from storage 2016-06-05 18:23:24 +10:00
ce23ad5615 Fix NPE 2016-06-05 18:07:41 +10:00
0b1153da21 Include other config files in DebugPaste 2016-06-05 17:43:40 +10:00
386157edc1 fix reserved flags 2016-06-05 17:35:44 +10:00
b7a8c8ecd6 Don't need this 2016-06-05 17:33:06 +10:00
951a6b82a2 simplify config / multiple expiry tasks / block cache fix 2016-06-05 17:28:43 +10:00
70aaa984e2 Documentation and Flag Changes. 2016-06-04 17:19:37 -04:00
17ff6a7e1d Merge pull request #1157 from MisterErwin/master
Fixed invalid condition
2016-06-05 04:34:47 +10:00
281f60a4ef Fixed invalid condition 2016-06-04 20:26:32 +02:00
ca5d3a818b PlotBlock cache / events / flags 2016-06-04 06:20:13 +10:00
f84766074e Fixes #1145 2016-06-04 03:36:39 +10:00
7dba332455 Debug a player is added to the known list. 2016-06-03 11:17:08 -04:00
b4707c94c4 Fix #579
Also tweaks to deprecation for development purposes.
2016-06-03 10:57:25 -04:00
0147690eba Make Sponge compile
It doesn't work but it allows the project to compile.
2016-06-02 19:38:35 -04:00
cee970e3d9 Tweaked some things 2016-06-02 13:42:32 -04:00
da58c7b411 Beautify code 2016-06-02 11:38:47 -04:00
8e306a92e3 Condense HttpUtil 2016-06-02 09:59:54 -04:00
89c4ce24ef Merge branch 'fix/forcefieldflag' of https://github.com/manuelgu/PlotSquared into manuelgu-fix/forcefieldflag 2016-06-02 09:52:30 -04:00
e6433a24ab Fix grow flags 2016-06-02 00:33:50 -04:00
f21d159911 Various fixes and tweaks. 2016-06-01 16:50:35 -04:00
042d8950ee Fix #1139 2016-05-29 20:48:14 -04:00
8d6565c32c Fix NPE 2016-05-29 19:38:31 +02:00
def33bc9ad Fix IntellectualSites/PlotSquared#1140 2016-05-29 11:59:16 +02:00
53e4b728a6 Merge remote-tracking branch 'origin/master' 2016-05-28 22:38:10 -04:00
4af846967c Fix #958 2016-05-28 22:37:56 -04:00
9ae4f02205 Fix forcefield flag 2016-05-28 01:16:01 +02:00
85055320c2 Merge pull request #1134 from manuelgu/feature/componentevent
[WIP] Implement PlotComponentSetEvent
2016-05-28 09:13:04 +10:00
d7b2881778 Don't * import 2016-05-28 01:12:05 +02:00
a7c965c6b0 Merge branch 'feature/componentevent' of https://github.com/manuelgu/PlotSquared into feature/componentevent 2016-05-28 01:09:25 +02:00
ec4839ec3f Move event calling to Plot class 2016-05-28 01:09:13 +02:00
b5cc6eeb0c Merge remote-tracking branch 'origin/master'
# Conflicts:
#	Sponge/src/main/java/com/plotsquared/sponge/SpongeMain.java
2016-05-28 08:45:35 +10:00
4078f0708b Proper javadoc for event 2016-05-28 00:29:27 +02:00
28a5c9f597 Remove pre-init logging 2016-05-28 02:01:50 +10:00
604f62dbd3 Remove dumb log statement 2016-05-27 11:10:36 -04:00
6c40ed7718 Fix Titles 2016-05-27 10:54:06 -04:00
e615fb4c44 Merge remote-tracking branch 'origin/master' 2016-05-26 09:19:50 -04:00
cc2d99849b Optimizations and javadoc tweaks 2016-05-26 09:19:38 -04:00
ceb8fb9fa3 Implement PlotComponentSetEvent 2016-05-25 21:49:55 +02:00
d44ca23abd Minor change to issue template (#1132) 2016-05-25 15:14:16 -04:00
ef60aeb017 Minor change to issue template 2016-05-25 20:54:26 +02:00
88ad051637 Direction/chance for bo3 2016-05-26 04:14:47 +10:00
465f7f4504 Tweaks and doc updates. 2016-05-24 22:08:45 -04:00
83f664129f Fixes #1130 2016-05-23 17:27:40 +10:00
a2a43816ad *And this 2016-05-23 04:41:25 +10:00
7bdcde6d24 Why was this made private? 2016-05-23 04:12:11 +10:00
89442a0e77 Fix visit 2016-05-22 07:13:59 +10:00
b8afbe8a00 Optimize auto trim + command cost/confirmation 2016-05-22 05:29:27 +10:00
e2182260d9 Fix Sponge Errors 2016-05-21 12:55:06 -04:00
6f26e42251 Fix Sponge Errors 2016-05-21 12:54:50 -04:00
13b7a798e6 ignored exception 2016-05-21 11:54:00 -04:00
8af30667e4 ignored exception 2016-05-21 11:18:35 -04:00
4bd83ab298 Logger changes 2016-05-21 11:16:21 -04:00
7ae5042c32 Recover from bad data file
Closes #1122
2016-05-22 01:16:04 +10:00
3ea2d06e70 Closes #1124 2016-05-22 01:11:27 +10:00
4ceb54b566 Add logger 2016-05-22 00:47:14 +10:00
dc4776d16b Sponge changes. 2016-05-21 10:39:06 -04:00
b51d659ff9 Merge remote-tracking branch 'origin/master' 2016-05-20 20:29:32 -04:00
1768943360 Register flags 2016-05-20 20:29:16 -04:00
6b1298a5e6 *Fix version check 2016-05-20 05:10:46 +10:00
b125ef6668 Add git revision hash to version 2016-05-20 03:32:35 +10:00
82e162ae00 * 2016-05-20 03:29:51 +10:00
5665e9b709 Fix merging sometimes not removing intersection 2016-05-20 03:25:45 +10:00
6bad640cec Fixes #1037 2016-05-19 18:53:07 +10:00
7873bcf592 Fixes #1102 2016-05-19 18:28:06 +10:00
75c7fe969c Fixes #1008 2016-05-19 18:20:23 +10:00
1df9ae77ab Fixes #1111 2016-05-19 18:13:37 +10:00
78796ca7b4 Fixes #1117 2016-05-19 18:09:12 +10:00
1ece792e2b Create parent directory for bo3 2016-05-18 16:35:37 +10:00
1b9c92fd4a Fix #1067 2016-05-17 21:52:36 -04:00
18e3a7553e Fix #1085
Fix #1085
2016-05-15 22:05:52 -04:00
64f3e8f79b Fixes #1116 2016-05-15 01:54:12 +10:00
c70c2283a2 Recover from failed event registration 2016-05-14 23:50:43 +10:00
4b962c35ab Merge pull request #1118 from manuelgu/apilocationremoval
Remove unused API Location that got printed on startup
2016-05-14 21:46:20 +10:00
72096db8d6 Remove unused API Location that got printed on startup 2016-05-14 12:33:52 +02:00
2039cb2891 Merge pull request #1112 from manuelgu/stuffnthings
Method renaming, util class and logic change
2016-05-14 15:04:11 +10:00
a5a001130c Fetch latest vesion on command
PS.get().update would return the URL of the latest update at the time
the server was started. Not everybody is restarting their servers daily
so it might end up in people not noticing an update in a long while
2016-05-13 19:09:40 +02:00
c1bc3dfc29 Add HttpUtil utility class 2016-05-13 19:07:56 +02:00
7701e7f05f Beautify listing of plot areas 2016-05-13 19:05:50 +02:00
2c0743b7e9 Proper method name 2016-05-13 19:04:55 +02:00
00340d5154 Important fix 2016-05-14 01:13:08 +10:00
d47eeff23b Cleaning and Fix #1108 2016-05-12 18:00:38 -04:00
0958b57e46 Tidy code. 2016-05-12 17:09:35 -04:00
7947c3fdd7 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-05-12 15:43:44 -04:00
0095af0ce5 Flag info 2016-05-13 03:38:32 +10:00
dee8072d83 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared
# Conflicts:

#	Bukkit/src/main/java/com/plotsquared/bukkit/listeners/PlayerEvents.java

#	Bukkit/src/main/java/com/plotsquared/bukkit/util/block/FastQueue_1_9.java
2016-05-13 03:04:43 +10:00
63c7041a34 Flag tweaks 2016-05-13 02:55:57 +10:00
63472ebeaf Merge branch '3.3.4'
# Conflicts:
#	Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java
2016-05-11 16:45:17 -04:00
d5cf81be5c 1.9.4 compatibility. 2016-05-11 12:11:46 -04:00
1db3d1aa72 Start 3.3.4 work to support 1.9.4 2016-05-11 11:16:38 -04:00
a4647b05e2 Fix #1011 2016-05-10 14:24:02 -04:00
3be0f74498 Fix #1098 2016-05-10 13:41:59 -04:00
e63b436edd Possible build everywhere fix. 2016-05-06 22:05:31 -04:00
1535c5e2f5 Fix test file 2016-05-05 13:41:11 -04:00
894524f998 Fix test file 2016-05-05 13:39:54 -04:00
8925c66b6e Fix file name 2016-05-05 13:19:15 -04:00
e4350feb2a Fixed missing type change 2016-05-05 13:17:17 -04:00
5d8492b675 Fixes cast exception 2016-05-05 13:13:55 -04:00
421203a27d Bug Fix and Cleanup 2016-04-29 18:14:12 -04:00
8f3d35bca3 Bug Fix and Cleanup 2016-04-28 16:38:51 -04:00
669359cd37 General changes 2016-04-26 10:14:22 -04:00
2c16c767e7 Fix flag values being loaded as strings 2016-04-26 08:40:52 -04:00
d8849f718c Fix plotworld get 2016-04-26 09:32:16 +10:00
8c56affb2f Fix for paint 2016-04-25 03:58:47 +10:00
1bce69d288 Merge flags to master 2016-04-22 23:54:53 -04:00
c266b1a428 Merge flags to master 2016-04-22 23:54:19 -04:00
e57af63af4 Possible remove fix. 2016-04-22 23:46:16 -04:00
3e4dbe0fbf fix compile error 2016-04-22 23:46:16 -04:00
74ed10c376 Completed and ready to test 2016-04-22 23:46:16 -04:00
aaf9511673 Start implementing new Flag system. 2016-04-22 23:46:16 -04:00
d3dd88eb8d Fixes #1062 2016-04-22 23:45:19 -04:00
9b22f38ff0 Fix plot download/done 2016-04-22 23:45:19 -04:00
10bf03f81b Disable colored chat 2016-04-22 23:45:19 -04:00
7c12a20a2b perm requirement for add/trust * 2016-04-22 23:45:19 -04:00
40e063e702 Fixes #1050 2016-04-22 23:45:19 -04:00
1c04b1a0e0 Fixes #1062 2016-04-19 15:32:31 +10:00
02d17b363d Fix plot download/done 2016-04-17 03:55:55 +10:00
d34abf4f02 Disable colored chat 2016-04-17 03:11:05 +10:00
30a2c5d881 perm requirement for add/trust * 2016-04-13 03:35:14 +10:00
76c3879c1f Fixes #1050 2016-04-13 02:41:40 +10:00
c2c20ff189 Merge remote-tracking branch 'remotes/origin/master' 2016-04-11 17:04:52 -04:00
588f5d7ebc Fixes #1047 2016-04-09 22:48:27 +10:00
9ba3b06854 change priority to low 2016-04-07 20:05:02 +10:00
45b6950111 Fixes chat error / plot deny * 2016-04-07 03:33:49 +10:00
8b10b7109c Merge remote-tracking branch 'origin/master'
# Conflicts:

#	Bukkit/src/main/java/com/plotsquared/bukkit/util/block/FastQueue_1_8_3.java

#	Bukkit/src/main/java/com/plotsquared/bukkit/util/block/FastQueue_1_9.java
2016-04-07 02:33:23 +10:00
f7810860da Re-add WorldEdit check 2016-04-07 02:14:50 +10:00
4dcac29028 Weaken Declaration 2016-04-06 00:17:30 -04:00
d49de5297b Tweaks 2016-04-05 23:50:04 -04:00
c5282b29b2 Merge remote-tracking branch 'origin/master' 2016-04-05 19:10:57 -04:00
3df772aa4e Fixed #852 and small changes
Hid updater error when debugging is not enabled.
Javadoc changes
2016-04-05 19:10:26 -04:00
de97028a20 Merge pull request #1045 from IntellectualSites/3.4.0 2016-04-05 12:55:06 -04:00
9c81dfa5c3 Cleanup and Optimizations
Abstracted TitleManagers
Removed a lot of Statics.
ETC.
2016-04-05 12:53:40 -04:00
fab60a0d53 Fix schematic on claim/auto 2016-04-05 11:07:37 +10:00
1f32707ec2 Fix populate offset for older versions 2016-04-05 10:08:10 +10:00
95c9fd01dd Merged 2016-04-04 12:49:11 -04:00
3c5e7a1509 version 2016-04-04 19:35:47 +10:00
6ea1383027 Merge pull request #1042 from manuelgu/feature/tpondeath
Add teleport on death feature
2016-04-04 19:35:44 +10:00
6ab3a029b2 Add teleport on death feature 2016-04-04 11:31:15 +02:00
b1cb6c0f57 Merge pull request #1038 from manuelgu/feature/bypassbreakbedrock
Add bypass permission for breaking blocks at y0
2016-04-04 18:46:57 +10:00
c69c4dd2e1 It actually is tested 2016-04-04 00:11:32 +02:00
4da38a6f9c Add bypass permission to breaking blocks at y0 2016-04-04 00:09:46 +02:00
dffa00858d More than 2 lines 2016-04-02 17:15:36 +11:00
4ebd778c62 Optimizations and a purge fix 2016-04-02 01:30:26 -04:00
8243e0118a Optionals introduced, code cleaned, potential purge fix 2016-04-01 19:14:46 -04:00
3edfd39af9 Bump Version 2016-04-01 09:30:13 -04:00
b7ebde874f Clean gradle target directory 2016-03-31 21:27:29 -04:00
8978d3b9a7 Update Gradle to 2.12 2016-03-31 16:45:07 -04:00
b909792d6a typo in disable titles 2016-04-01 06:54:28 +11:00
4a7112a0a5 Various
Add some 1.9 blocks to chest content with schematic paste
Restructure tileentity placement from schematic (will soon add signs
etc)
Prepare for release 3.3.3
2016-04-01 04:23:26 +11:00
edd18a7178 Various
- Fix some block change issues (for some reason sending a chunk would
sometimes reset any recent changes)
- Send chunk changes for relight command
- Have kick cmd kick the player from the server if they are kicked from
the spawn plot
- Plot size checks for downloading
- Fix some potential integer overflow issues for large plots (>64K x
64K)
- Fix some edge cases for plot move/copy
2016-03-31 20:49:00 +11:00
dbdd9f9e5a Merge pull request #1026 from manuelgu/feature/fixes
Fixes and cleanup
2016-03-31 20:42:31 +11:00
25dfc34695 Comma-separate plot area list again 2016-03-30 15:25:25 +02:00
ea17ba8e46 Fix sponge conflicts 2016-03-30 15:09:00 +02:00
6fc8bf587b Comma-separate list of plot worlds 2016-03-30 14:43:16 +02:00
429fed2ab3 Fix target command
Threw an exception when you didnt pass an argument
2016-03-30 14:43:04 +02:00
510b9a47dc Formatting 2016-03-30 14:42:41 +02:00
44e11e9c6b Add command to list all available scripts
Additional debugexec subcommand
2016-03-30 14:42:34 +02:00
95d03e878c Cancel potion throw 2016-03-30 13:41:13 +11:00
dca2696782 Forgot wall height 2016-03-30 13:26:23 +11:00
1e93398fd8 Cancel lingering potion splash
Cancelling the event still doesn't stop the animation.
2016-03-30 13:23:31 +11:00
1f6ad47a79 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	Bukkit/src/main/java/com/intellectualcrafters/plot/api/PlotAPI.java
2016-03-30 12:12:19 +11:00
312ad4c48c fix index 2016-03-30 12:09:55 +11:00
31d346a587 Minor code cleanup
Plus an optimization
2016-03-29 17:00:07 -04:00
6007f040cd OCD 2016-03-29 15:47:59 -04:00
d0622eb87d PlotAPI doc and code cleaning 2016-03-29 14:35:40 -04:00
6ebfd426c3 Just "height" would have made more sense 2016-03-30 05:14:51 +11:00
bbe43f782c Fix nested command configuration 2016-03-30 04:47:47 +11:00
560ebf412b Relight command 2016-03-30 04:34:48 +11:00
df630f9be1 Remove outdated copyright notice at the top of each file
- No license is the same as all rights reserved
- There's already a license at the root of the project
- The message was not in most files. easier to remove it
- Support link isn't valid
- No longer just the bukkit API
2016-03-30 02:50:13 +11:00
578e884be7 Merge pull request #1025 from manuelgu/master
Cleanup
2016-03-29 20:08:33 +11:00
22f56d4da6 Remove ChatColor
Sponge support
2016-03-29 10:57:27 +02:00
745f9c4858 Buy 2016-03-29 19:52:57 +11:00
5f2856e0ea Cleanup
Consistent use of String[] instead of String...
Removed unused variables
2016-03-29 10:47:56 +02:00
d9c6d04b46 Debug PlotMe conversion (temporary) 2016-03-29 19:13:48 +11:00
8244086840 Merge pull request #1024 from dmodoomsirius/master
Revert "have clean help delete the output directory"
2016-03-29 19:13:00 +11:00
e282998765 Revert "have clean help delete the output directory"
This reverts commit afa9935a7a.
2016-03-29 04:11:25 -04:00
bd633c0150 Merge pull request #1023 from dmodoomsirius/master
Give the ability to clean the output directory
2016-03-29 19:00:57 +11:00
5ec6bc62ca Merge branch 'master' of https://github.com/dmodoomsirius/PlotSquared 2016-03-29 03:59:42 -04:00
afa9935a7a have clean help delete the output directory
to make things nice and clean
2016-03-29 03:59:12 -04:00
512ae38392 Fix plot kick args 2016-03-29 18:57:35 +11:00
19ef76de33 Oh, and this 2016-03-29 18:51:10 +11:00
638f267498 Remove required args for visit 2016-03-29 18:48:07 +11:00
bc8becae8e Check for null 2016-03-29 18:47:04 +11:00
6f9af04274 Cleanup BukkitChunkManager 2016-03-29 18:44:04 +11:00
75a70bcff4 Merge pull request #1022 from EvilOlaf/patch-1
Missing brackets
2016-03-29 18:11:12 +11:00
30043fd1c1 Missing brackets
very (VERY!) minor change ^^
2016-03-29 09:10:24 +02:00
ef4438889b Fix plot move 2016-03-29 18:09:40 +11:00
9bd3f2cbfd Fix plot list add 2016-03-29 17:56:48 +11:00
eed8cbec5a Fixes #1015 2016-03-29 17:39:29 +11:00
5f8a55568c Fix plot rate categories 2016-03-29 17:21:58 +11:00
5275d4ec62 Fix "cleanup" breaking plugin again 2016-03-29 17:13:19 +11:00
30dc20b3b3 Fix "Fixes #1015" not resetting the home location.
Resetting involves clearing the current value i.e. so it respects
whatever is set in the config, if that value is changed.
2016-03-29 17:06:58 +11:00
32ba55baf5 Code cleanup and Optimizations 2016-03-29 00:56:44 -04:00
49d18b9229 Code cleanup 2016-03-28 23:26:44 -04:00
a8fd6d00d0 Sorry for the versioning confusion 2016-03-28 23:23:56 -04:00
b1fa258688 Code cleanup 2016-03-28 19:30:55 -04:00
874da8c5bc Merge pull request #1019 from manuelgu/master
Fixes #1018
2016-03-28 18:17:45 -04:00
76e2b1f416 Code cleanup
maybe a bug fix or two
2016-03-28 17:31:40 -04:00
83fa310fbb Fix ArrayIndexOutOfBoundsExceptions
Occured for /plot trust and /plot add
2016-03-28 23:18:29 +02:00
8d4f042abc Cleanup of code 2016-03-28 13:28:21 -04:00
feee63b3af Fix DebugLoadTest 2016-03-28 13:02:20 -04:00
c4f5905252 Merge pull request #1016 from manuelgu/master
Fixes #1015
2016-03-28 11:25:33 -04:00
c2e48bb95b Fixes #1015 2016-03-28 16:27:32 +02:00
d9c0ec27b0 Fixes #774 2016-03-28 23:04:08 +11:00
dcd1a50a0c default tab completion + plot chat for merged plots 2016-03-28 22:52:29 +11:00
b6bdb02fa2 Merge pull request #1012 from manuelgu/master
Update Plugin command to show correct versions
2016-03-28 07:23:07 -04:00
8f0de80755 Update Plugin command to show correct version
Not using PS.get().update but rather reading from the GitHub releases. Can be changed if needed/wanted
2016-03-28 11:29:58 +02:00
978be89e52 Fix bug causing the Updater to not work. 2016-03-27 23:48:24 -04:00
93ef066d7b 3.3.3-SNAPSHOT Beginning
Sponge Gradle Changes
2016-03-27 18:55:57 -04:00
ff1b7c66b1 What's snow-melt doing there? 2016-03-27 19:38:15 +11:00
3fb6ccbbb6 Fix TNT explosions for sponge 2016-03-27 19:10:08 +11:00
357400c5ac Fix block break road (sponge) 2016-03-27 17:01:49 +11:00
32e10fbff6 Fix permission caching (sponge) 2016-03-27 16:19:56 +11:00
1bf05df706 Try this coolty 2016-03-27 16:01:53 +11:00
e3f5842299 Recover from invalid db entry 2016-03-27 07:31:35 +11:00
53e56a6414 Fix required args 2016-03-27 07:11:09 +11:00
46d3dc609e Update sponge port 2016-03-27 06:47:34 +11:00
056f77a3ba 3.3.2 2016-03-27 03:34:55 +11:00
d4d9a9e148 Change to SubCommand 2016-03-26 20:28:45 +11:00
6a7cf0d56f forgot to push this 2016-03-26 16:44:38 +11:00
1252e004a0 Cancel chat event 2016-03-25 15:56:11 +11:00
2816ceae72 Change chat priority 2016-03-25 15:07:35 +11:00
f74e7bb4cb Fixes #997 for 1.8 2016-03-25 14:50:57 +11:00
30d57d8642 Fixes #997 for 1.9 (TODO fix for 1.8 as well) 2016-03-25 14:25:06 +11:00
ce9ec20b59 Merge pull request #1000 from manuelgu/patch-1
Rename PlotGamemode to PlotGameMode
2016-03-24 23:09:51 -04:00
65d428a989 Rename PlotGamemode to PlotGameMode
@MattBDev I think you just forgot renaming the class
2016-03-24 23:06:45 +01:00
7ab8d22325 Move confirmation to commands.yml 2016-03-25 02:03:36 +11:00
ed62ed2487 Fixes #983 2016-03-24 22:08:07 +11:00
8a42eecc11 Command changes
Legacy commands still need to be cleaned up (after which economy /
confirmation can be centralized)
All command names / usage / description is configurable
Simplifies creating commands
Deeper tab completion / command help
2016-03-24 20:57:59 +11:00
a62b9a334d Cleaning 2016-03-24 00:50:25 -04:00
48f22eaed4 More cleaning 2016-03-23 13:13:09 -04:00
bb4700aa5a More cleaning 2016-03-23 13:09:13 -04:00
9e2c6f2182 Major code reformatting 2016-03-22 21:41:39 -04:00
e18e1d4816 Merge pull request #995 from manuelgu/master
Cleanup
2016-03-22 14:36:41 -04:00
35c7c20874 Track renamed Music.java file 2016-03-22 18:53:56 +01:00
84188f6557 Cleanup 2016-03-22 18:53:17 +01:00
09ee7f3048 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	Core/src/main/java/com/intellectualcrafters/plot/commands/Area.java
#	Core/src/main/java/com/intellectualcrafters/plot/commands/Auto.java
#	Core/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java
#	Core/src/main/java/com/intellectualcrafters/plot/generator/HybridUtils.java
#	Core/src/main/java/com/intellectualcrafters/plot/object/Plot.java
#	Core/src/main/java/com/intellectualcrafters/plot/object/PlotAnalysis.java
2016-03-20 23:03:31 -04:00
029241912b Code Style Cleanup 2016-03-20 22:52:16 -04:00
0e49dd6f62 Merge branch 'manuelgu-feature/rm-redundant-methods' 2016-03-20 19:54:46 -04:00
cb0b59fdb4 Merge branch 'feature/rm-redundant-methods' of https://github.com/manuelgu/PlotSquared into manuelgu-feature/rm-redundant-methods 2016-03-20 19:52:11 -04:00
bb4ecb94a1 Cleanup 2016-03-20 19:35:40 -04:00
df12e53d40 Remove redundant .s() methods 2016-03-20 23:19:37 +01:00
274d819f8c Use Metrics as dependency in Sponge
Unlike Bukkit, we can support Sponge Metrics as a dependency.
2016-03-20 14:00:39 -04:00
2e4f4d0064 Merge pull request #986 from SynergyMC/testing
A small change to /p weanywhere's behavior
2016-03-20 21:50:17 +11:00
712ce74af6 /p weanywhere change
Allows players with "WorldEdit Anywhere" toggled to use the wand
anywhere
2016-03-20 00:26:45 -10:00
015dda21f2 Merge remote-tracking branch 'IntellectualSites/master' into testing 2016-03-19 18:11:36 -10:00
19b6df8268 Cleanup 2016-03-19 14:07:55 -04:00
f16affabcc Merge remote-tracking branch 'IntellectualSites/master' into testing 2016-03-18 23:28:49 -10:00
8074d041b8 Fix "Cleaner reflection" breaking plugin.
Also add method to sort plots by modification date.
2016-03-19 17:32:05 +11:00
d30626d11f Cleaner reflection 2016-03-19 00:39:42 -04:00
f26278f72e Fixes #950 2016-03-19 13:01:10 +11:00
79864d269a Extremely minor text change to LICENSE 2016-03-18 16:50:43 -04:00
ab40d97327 Try this? 2016-03-18 05:08:09 +11:00
fe43143bdb Fixes #972 2016-03-18 03:33:31 +11:00
9e32ce9885 Automatically drop unique_alias for MySQL 2016-03-18 03:05:36 +11:00
3921fdfc3f Fixes #967 2016-03-18 02:18:18 +11:00
e1e5497558 Fixes #871 2016-03-18 02:06:06 +11:00
f9db269813 Various
Close #966
Close #953
(duplicates)
Changes to chunk copying etc to interfere less with world generation
2016-03-18 01:22:51 +11:00
16dac99fed Any reason for breaking it in the last commit? 2016-03-17 20:33:47 +11:00
98c4483535 Various
some sponge stuff
schematic/mca/bo3 uploading rework
fix minor issue with plot visit
fix #956
2016-03-17 20:11:07 +11:00
75bf01c13f Fixed casting issue in FastQueue_1_9 2016-03-16 19:18:09 -04:00
7bbd359be8 Fixed #957 2016-03-16 18:50:55 -04:00
58eeeb16d4 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-03-16 10:16:19 -04:00
65ddb12701 Beginning rewrite of Flags and various cleanups 2016-03-16 10:15:38 -04:00
1f42ee6744 Merge pull request #969 from SynergyMC/testing
Implements fire-related flags
2016-03-17 01:06:00 +11:00
4a1c206f98 Revert "Fixed bukkit dependency in maven"
This reverts commit e6f33e7150.
2016-03-15 22:25:31 -10:00
a297d505f8 Pulled files from official repository 2016-03-15 22:15:47 -10:00
a26db46242 Pyromania
Adds block-ignition, which allows fire being set by players,
dispensers, explosions, and fireballs (if their origin is the same as
the plot that they land in)

Adds fire-spread, which allows fire to spread from lava and fire
spreading in general

Adds block-burn, which allows blocks to burn away
2016-03-15 21:59:01 -10:00
3fb64d9811 Added snow-melt flag 2016-03-15 01:16:29 -04:00
bb8883dfaf Added snow-melt flag 2016-03-14 11:01:52 -04:00
bee6f83e79 Various changes 2016-03-14 02:18:04 -04:00
ae885eafca Various changes and Merge Economy Fix 2016-03-13 22:44:59 -04:00
8739f3ef78 Horses aren't hostile. 2016-03-14 12:34:58 +11:00
dfd29f6713 Various changes
Plot class is now more reliable as most fields are private
Cleanup some classes.
Fixes #955
makes progress on #953
2016-03-13 14:09:48 -04:00
e6f33e7150 Fixed bukkit dependency in maven 2016-03-12 23:37:45 -10:00
3fb686608b Merge pull request #951 from Gabscap/fix-static
Make WorldEvents method non-static
2016-03-13 04:00:40 +11:00
a8fd1b49ca Various
sponge changes / documentation / cleanup / event tweak
2016-03-13 03:57:36 +11:00
4c40268e8f Make WorldEvents method non-static 2016-03-12 16:27:03 +01:00
edc43bd53b Update README.md 2016-03-11 09:05:42 -05:00
66da71bc9f Various
Fixes a few typos
Fixes #943
Fixes #944
Fixes metrics (broke in b69e31129d)
Fixes plot setup issue
Fixes some lighting issues
Fixes ChunkListener + cauldron
Tweak some  schematic stuff
2016-03-11 15:33:39 +11:00
c979be2994 Add missing permission to plugin.yml file 2016-03-10 17:12:56 -05:00
33222b25a3 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-03-08 21:41:47 -05:00
57fa265b48 Optimizations and cleaning.
Fixes #943 (even though it should be impossible)
2016-03-08 21:18:54 -05:00
fef2bc0cf2 Restore metrics 2016-03-08 16:31:40 +11:00
f391ae444f remove java 8 code 2016-03-08 14:09:50 +11:00
286e5b8b97 Minor performance improvements. 2016-03-07 15:28:59 -05:00
d2c81cbd01 Use Metrics Dependency 2016-03-07 14:56:06 -05:00
e4d460107f Update ISSUE_TEMPLATE.md 2016-03-07 11:24:36 -05:00
b59665b00b Fix #938 2016-03-07 19:37:53 +11:00
62531a42c7 Fix for @Htgan / clear
Possibly fixes #932
2016-03-07 17:34:57 +11:00
05caa2ca8d Fixes #935 2016-03-06 23:46:37 +11:00
00c174fdf1 Various
Progress on #929
Fix area loading from config with negative ids @skroob
2016-03-06 19:08:01 +11:00
b95fdeccca Maybe? 2016-03-06 19:08:01 +11:00
32d4a08db1 Small cleanup 2016-03-04 19:53:31 -05:00
5c60d69fd1 closes #915 2016-03-04 16:37:38 -05:00
780d4e09d5 Delay economy hook #922 2016-03-04 05:04:11 +11:00
2b3fb7b4d0 Fix for explosion 2016-03-03 12:25:57 +11:00
0dc672bcd5 Apparently resetTitles only resets the top part? 2016-03-03 09:12:20 +11:00
6e2256ffcf Update titles 2016-03-03 09:08:43 +11:00
cfcfd87f57 messy nms for 1.9 2016-03-03 08:51:17 +11:00
955f14e2d7 Merge pull request #920 from manuelgu/patch-4
Formatting in pom.xml
2016-03-03 08:12:48 +11:00
4ead7bb9da Formatting in pom.xml
Because that just looks better :P
2016-03-02 22:11:28 +01:00
0408e9a37c Sorry, I'll fix it. 2016-03-03 07:34:59 +11:00
b294ff528f Push file for legacy updater 2016-03-02 17:49:17 +11:00
f00ac79c91 Bump version / misc
Fix regenallroads
Add schematic y_offset
Change visit/list for multi-owner plots
Fix updater (pre-1.7.10)
2016-03-02 17:42:04 +11:00
109715e0d7 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-03-02 06:59:05 +11:00
8bf3ceac6f Changes
Plot auto clear confirmation
Add timediff to keep flag
Add expired parameter to list cmd
Fixes some compatibility issues
2016-03-02 06:56:50 +11:00
106c3c5cb4 Temporary fix for 1.9 2016-03-01 14:17:29 +11:00
0bbfd0f49a Begin 1.9 NMS updates 2016-02-29 20:44:58 -05:00
9596544f97 Cleanup Code
I also updated the build.gradle and pom to 1.9 bukkit
2016-02-29 20:13:18 -05:00
5079361fbf Fix negation issue. 2016-02-29 11:50:04 -05:00
b0a3f70cbd Updater now uses GitHub Releases and API 2016-02-29 11:15:51 -05:00
841809b93d Various
Closes #906
Add command confirmation for setowner
Require confirmation delayed by 1 tick
2016-03-01 02:01:52 +11:00
43b7a7aba8 Fixes #910 2016-02-29 15:12:20 +11:00
8906577699 Merge pull request #909 from zombachu/master
Implements the ice-melt flag
2016-02-29 14:08:31 +11:00
224caee56e Implements the ice-melt flag 2016-02-28 15:41:32 -10:00
5c4178b1dd Fixes
Fixes #905
Fixes auto claim limit
2016-02-29 04:09:09 +11:00
911bef974a Stop spectating before being kicked when denied.
Fixes #886
2016-02-27 20:11:18 -05:00
7d340b58b4 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-02-27 15:49:45 -05:00
ce8775414a Fix some logic 2016-02-28 07:04:57 +11:00
5da8700f7f Force Core to use Java 7 2016-02-27 13:41:49 -05:00
01710e3ddb Fixes
Notify core of all world loading regardless of generator
Optimize plot area fetching
Fix plot delete not deleting the plot until restart
Fix plot unclaim not removing the owner on any cached plots
Change gradle output directory
Fix plotme conversion sometimes not copying over the floor/main blocks
2016-02-27 21:07:42 +11:00
7d8893b5d7 Fixes #900 2016-02-27 17:07:15 +11:00
7a97c69d4f Fix bed explosion in hell biome when flag not present 2016-02-27 16:44:29 +11:00
1a80b344b9 replace jar with one that's less broken 2016-02-27 16:09:55 +11:00
afe6c5fd69 Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-02-27 16:05:56 +11:00
f68042bc11 Fixes
Fixes unlink failing if a parameter is provided
Fix plot unlinking not resetting the road biome
Fixes #888
2016-02-27 16:05:21 +11:00
ac77c755d0 Add plot middle permission to plugin.yml 2016-02-26 19:10:59 -05:00
c7870b617c Gradle / maven
Fix archive names (includes project/module name + version)
Generate MD5 hash alongside jar
Improve build time
- asynchronous building
- enable daemon
- change scope of a few statements
- skip building of 3 jars
Add filtering to the plugin.yml (maven/gradle)
Bump version to 3.3.0 in pom
2016-02-26 23:55:21 +11:00
f921db937a Fix plot music duplication when moving between plots in a merged plot 2016-02-26 17:43:49 +11:00
4669f31658 Fixes
Fixes hybridplotworld rotation for stairs
Fixes hybridplotworld skipping non-rotatable blocks on swapped sideroad
schem
Fixes schematic generation using wrong height
Fixes debug spam printed when using download cmd
Fixes pagination having page number instead of total list items
Fixes plot area list page being off by 1
Remove compatibility for a spigot 1.8.0 bug where getting the world name
during initialization crashes the server.
Fixes type 1,2 plot worlds not being fetchable if there are more than 8
plot worlds loaded.
2016-02-26 17:29:31 +11:00
c8ddcd7f54 Fixes
Fix plot cluster command NPE
Fix path iterator (for Plot.getAllCorners()) being off by 1
2016-02-26 04:17:23 +11:00
fb2e949711 Fix rotation for stairs metadata (range:8-15) 2016-02-26 01:21:30 +11:00
7659884e73 Fixes
Fixes #868
Fixes #778
Fixes attributes passing wrong key to persistent meta
Fixes blob compatibility with JDBC driver for persistent meta
Fix stackoverflow from countEntities under certain circumstances
Minor cleanup
2016-02-26 01:17:07 +11:00
efae2c2e63 Finished several core parts of the sponge port
Mass block changes / chunk packet sending
AsyncWorldEdit (buggy)
Fixed world ground cover layers being generated
Fixed tab completion
Fixed plot title color
Fixed worlds unloading when no players are present
Fixed falling blocks not falling where they should
Fixed console color
Fixed chunk regeneration on full plot worlds
Other stuff
2016-02-25 20:13:07 +11:00
d3465b7bde Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-02-24 05:12:20 +11:00
f73a542b04 Tab completion, fix SpongeUtil.getWorld 2016-02-24 05:12:07 +11:00
6f3485c87d Hard-code version into plugin.yml 2016-02-23 13:08:20 -05:00
bf85ba5833 No they aren't 2016-02-24 04:20:40 +11:00
8a2c44759f Chunk regeneration 2016-02-24 04:04:23 +11:00
882394987b Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-02-24 03:08:12 +11:00
7a217b2f08 a wild pom appears
fork/pr if you don't like how I've done it
2016-02-24 03:07:49 +11:00
b94e816c55 Sponge changes. 2016-02-23 09:55:40 -05:00
87ee693a49 Fix small Gradle things. 2016-02-22 23:30:49 -05:00
1768651782 Merge pull request #874 from IntellectualSites/gradle
Move from Maven to Gradle
2016-02-22 23:16:03 -05:00
b69e31129d Updated Gradle 2016-02-22 23:11:40 -05:00
7b15d50674 Add PS.get().isPlotWorld() and MainUtil.getPlotID( Location );
@_Cory_
2016-02-23 05:46:57 +11:00
f996b1d95d Using ReflectionUtils simplifies stuff? 2016-02-23 05:38:28 +11:00
14eb3279c0 Revert version 2016-02-23 05:31:35 +11:00
ced342f14e Merge branch 'master' of https://github.com/IntellectualSites/PlotSquared 2016-02-22 17:24:30 +11:00
f5ff82c8cc Sponge / Other
Fix area teleportation for type 0,1 worlds
Add blockstate<>id/data resolving for sponge
Finish world generation for sponge
Add chat color for sponge
Fix economy support for sponge
Fix sponge event system
Other stuff
2016-02-22 17:20:22 +11:00
b255c5db47 Cleanup and Fixes
Fixed StackOverflowError caused by c83378a
2016-02-21 23:29:33 -05:00
ca5e7f4564 Cleanup 2016-02-20 23:07:04 -05:00
ef5846f688 Cleanup 2016-02-20 16:50:10 -05:00
36ebd1983d Use UTF-8 2016-02-19 15:51:04 -05:00
719 changed files with 61762 additions and 54725 deletions

View File

@ -1,12 +1,22 @@
# Bug report template (clear for feature request) # Bug report template
**Debug paste link**: <!--- In order to create a valid issue report you have to follow this template. -->
<!--- Incomplete reports might be marked as invalid. -->
<!--- You may remove it if you are posting a feature request. -->
**Debug paste link:**
<!--- Enter /plot debugpaste in game or in your console and copy the output here -->
**Description of the problem:** **Description of the problem:**
**How to replicate**:
Make sure you've completed the following steps (put X inside of brackets): **How to replicate:**
- [ ] Include `/plot debugpaste` <!--- If you can reproduce the issue please tell us as detailed as possible step by step how to do that -->
- [ ] Made sure there aren't duplicates of this report [(Use Search)](https://github.com/IntellectualSites/PlotSquared/issues)
- [ ] Made sure you're using an updated version of PlotSquared **Checklist**:
- [ ] Made sure the bug/error isn't caused by any other plugin <!-- Make sure you have completed the following steps (put an "X" between of brackets): -->
- [] I included a `/plot debugpaste` link
- [] I made sure there are no duplicates of this report [(Use Search)](https://github.com/IntellectualSites/PlotSquared/issues?utf8=%E2%9C%93&q=is%3Aissue)
- [] I made sure I am using an up-to-date version of PlotSquared
- [] I Made sure the bug/error is not caused by any other plugin

14
.gitignore vendored
View File

@ -1,10 +1,14 @@
### Others ### ### Others ###
*.bat
*.cmd *.cmd
*.sh *.sh
*.prefs *.prefs
Sponge/build
Core/build
Bukkit/build
Nukkit/build
### Maven ### ### Maven ###
/mvn
/target/lib /target/lib
/target/maven-archiver /target/maven-archiver
/target/classes /target/classes
@ -59,6 +63,7 @@ hs_err_pid*
# Gradle: # Gradle:
# .idea/gradle.xml # .idea/gradle.xml
# .idea/libraries # .idea/libraries
.gradle
# Mongo Explorer plugin: # Mongo Explorer plugin:
# .idea/mongoSettings.xml # .idea/mongoSettings.xml
@ -128,3 +133,10 @@ local.properties
# STS (Spring Tool Suite) # STS (Spring Tool Suite)
.springBeans .springBeans
/target/ /target/
Nukkit/build/classes/
Nukkit/build/dependency-cache/
checkstyle.xml
classes/
p2error.txt
*.bat
Nukkit/build/resources/main/plugin.yml

45
Bukkit/build.gradle Normal file
View File

@ -0,0 +1,45 @@
repositories {
maven {url "https://hub.spigotmc.org/nexus/content/groups/public/"}
maven { url = "https://oss.sonatype.org/content/repositories/snapshots/"}
maven {url "http://nexus.hc.to/content/repositories/pub_releases"}
mavenLocal()
}
dependencies {
compile project(':Core')
compile 'org.spigotmc:spigot-api:1.11.2-R0.1-SNAPSHOT'
compile("net.milkbowl.vault:VaultAPI:1.6") {
exclude module: 'bukkit'
}
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
processResources {
from('src/main/resources') {
include 'plugin.yml'
expand(
name: project.parent.name,
version: project.parent.version
)
}
}
// We only want the shadow jar produced
jar.enabled = false
shadowJar {
dependencies {
include(dependency(':Core'))
}
relocate('org.mcstats', 'com.plotsquared.stats')
archiveName = "${parent.name}-${project.name}-${parent.version}.jar"
destinationDir = file '../target'
}
shadowJar.doLast {
task ->
ant.checksum file: task.archivePath
}
build.dependsOn(shadowJar);

View File

@ -0,0 +1,733 @@
package com.intellectualcrafters.plot.api;
import com.intellectualcrafters.configuration.file.YamlConfiguration;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.commands.SubCommand;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.flag.Flag;
import com.intellectualcrafters.plot.flag.FlagManager;
import com.intellectualcrafters.plot.flag.Flags;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.PlotManager;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.ChunkManager;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.Permissions;
import com.intellectualcrafters.plot.util.SchematicHandler;
import com.intellectualcrafters.plot.util.UUIDHandler;
import com.intellectualcrafters.plot.util.block.GlobalBlockQueue;
import com.intellectualcrafters.plot.uuid.UUIDWrapper;
import com.plotsquared.bukkit.util.BukkitUtil;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* PlotSquared API.
*
* <p>Useful classes:
* <ul>
* <li>{@link BukkitUtil}</li>
* <li>{@link PlotPlayer}</li>
* <li>{@link Plot}</li>
* <li>{@link com.intellectualcrafters.plot.object.Location}</li>
* <li>{@link PlotArea}</li>
* <li>{@link PS}</li>
* </ul>
* @version 3.3.3
*/
public class PlotAPI {
/**
* Deprecated, does nothing.
* @param plugin not needed
* @deprecated Not needed
*/
@Deprecated
public PlotAPI(JavaPlugin plugin) {}
public PlotAPI(){}
/**
* Get all plots.
*
* @return all plots
*
* @see PS#getPlots()
*/
public Set<Plot> getAllPlots() {
return PS.get().getPlots();
}
/**
* Return all plots for a player.
*
* @param player Player, whose plots to search for
*
* @return all plots that a player owns
*/
public Set<Plot> getPlayerPlots(Player player) {
return PS.get().getPlots(BukkitUtil.getPlayer(player));
}
/**
* Add a plot world.
*
* @param plotArea Plot World Object
* @see PS#addPlotArea(PlotArea)
*/
public void addPlotArea(PlotArea plotArea) {
PS.get().addPlotArea(plotArea);
}
/**
* Returns the PlotSquared configurations file.
* @return main configuration
*
* @see PS#config
*/
public YamlConfiguration getConfig() {
return PS.get().config;
}
/**
* Get the PlotSquared storage file.
* @return storage configuration
*
* @see PS#storage
*/
public YamlConfiguration getStorage() {
return PS.get().storage;
}
/**
* Get the main class for this plugin. Only use this if you really need it.
*
* @return PlotSquared PlotSquared Main Class
*
* @see PS
*/
public PS getMain() {
return PS.get();
}
/**
* ChunkManager class contains several useful methods.
* <ul>
* <li>Chunk deletion</li>
* <li>Moving or copying regions</li>
* <li>Plot swapping</li>
* <li>Entity Tracking</li>
* <li>Region Regeneration</li>
* </ul>
*
* @return ChunkManager
*
* @see ChunkManager
*/
public ChunkManager getChunkManager() {
return ChunkManager.manager;
}
/**
* Get the block/biome set queue
* @return GlobalBlockQueue.IMP
*/
public GlobalBlockQueue getBlockQueue() {
return GlobalBlockQueue.IMP;
}
/**
* UUIDWrapper class has basic methods for getting UUIDS. It's recommended
* to use the UUIDHandler class instead.
*
* @return UUIDWrapper
*
* @see UUIDWrapper
*/
public UUIDWrapper getUUIDWrapper() {
return UUIDHandler.getUUIDWrapper();
}
/**
* Do not use this. Instead use FlagManager.[method] in your code.
* - Flag related stuff
*
* @return FlagManager
*
* @deprecated Use {@link FlagManager} directly
*/
@Deprecated
public FlagManager getFlagManager() {
return new FlagManager();
}
/**
* Do not use this. Instead use MainUtil.[method] in your code.
*
* @return MainUtil
* @deprecated Use {@link MainUtil} directly
*/
@Deprecated
public MainUtil getMainUtil() {
return new MainUtil();
}
/**
* Do not use this. Instead use C.PERMISSION_[method] in your code.
*
* @return Array of strings
*
* @see Permissions
* @deprecated Use {@link C} to list all the permissions
*/
@Deprecated
public String[] getPermissions() {
ArrayList<String> perms = new ArrayList<>();
for (C caption : C.values()) {
if ("static.permissions".equals(caption.getCategory())) {
perms.add(caption.s());
}
}
return perms.toArray(new String[perms.size()]);
}
/**
* SchematicHandler class contains methods related to pasting, reading
* and writing schematics.
*
* @return SchematicHandler
*
* @see SchematicHandler
*/
public SchematicHandler getSchematicHandler() {
return SchematicHandler.manager;
}
/**
* Use C.[caption] instead
*
* @return C
* @deprecated Use {@link C}
*/
@Deprecated
public C[] getCaptions() {
return C.values();
}
/**
* Get the plot manager for a world. Most of these methods can be accessed
* through the MainUtil.
*
* @param world the world to retrieve the manager from
*
* @return PlotManager
*
* @see PlotManager
* @see PS#getPlotManager(Plot)
*/
@SuppressWarnings("deprecation")
@Deprecated
public PlotManager getPlotManager(World world) {
if (world == null) {
return null;
}
return getPlotManager(world.getName());
}
/**
* Get a list of PlotAreas in the world.
* @param world The world to check for plot areas
* @return A set of PlotAreas
*/
public Set<PlotArea> getPlotAreas(World world) {
if (world == null) {
return Collections.emptySet();
}
return PS.get().getPlotAreas(world.getName());
}
/**
* Get the plot manager for a world. Contains useful low level methods for
* plot merging, clearing, and tessellation.
*
* @param world The world
*
* @return PlotManager
*
* @see PS#getPlotManager(Plot)
* @see PlotManager
*/
@Deprecated
public PlotManager getPlotManager(String world) {
Set<PlotArea> areas = PS.get().getPlotAreas(world);
switch (areas.size()) {
case 0:
return null;
case 1:
return areas.iterator().next().manager;
default:
PS.debug("PlotAPI#getPlotManager(org.bukkit.World) is deprecated and doesn't support multi plot area worlds.");
return null;
}
}
/**
* Get the settings for a world (settings bundled in PlotArea class). You
* will need to downcast for the specific settings a Generator has. e.g.
* DefaultPlotWorld class implements PlotArea
*
* @param world The World
*
* @return The {@link PlotArea} for the world or null if not in plotworld
*
* @see #getPlotAreas(World)
* @see PlotArea
*/
@SuppressWarnings("deprecation")
@Deprecated
public PlotArea getWorldSettings(World world) {
if (world == null) {
return null;
}
return getWorldSettings(world.getName());
}
/**
* Get the settings for a world.
*
* @param world the world to retrieve settings from
*
* @return The {@link PlotArea} for the world or null if not in plotworld
*
* @see PS#getPlotArea(String, String)
* @see PlotArea
*/
@Deprecated
public PlotArea getWorldSettings(String world) {
if (world == null) {
return null;
}
Set<PlotArea> areas = PS.get().getPlotAreas(world);
switch (areas.size()) {
case 0:
return null;
case 1:
return areas.iterator().next();
default:
PS.debug("PlotAPI#getWorldSettings(org.bukkit.World) is deprecated and doesn't support multi plot area worlds.");
return null;
}
}
/**
* Send a message to a player.
*
* @param player the recipient of the message
* @param caption the message
*
* @see MainUtil#sendMessage(PlotPlayer, C, String...)
*/
public void sendMessage(Player player, C caption) {
MainUtil.sendMessage(BukkitUtil.getPlayer(player), caption);
}
/**
* Send a message to a player. The message supports color codes.
*
* @param player the recipient of the message
* @param string the message
*
* @see MainUtil#sendMessage(PlotPlayer, String)
*/
public void sendMessage(Player player, String string) {
MainUtil.sendMessage(BukkitUtil.getPlayer(player), string);
}
/**
* Send a message to the console. The message supports color codes.
*
* @param message the message
*
* @see MainUtil#sendConsoleMessage(C, String...)
*/
public void sendConsoleMessage(String message) {
PS.log(message);
}
/**
* Send a message to the console.
*
* @param caption the message
*
* @see #sendConsoleMessage(String)
* @see C
*/
public void sendConsoleMessage(C caption) {
sendConsoleMessage(caption.s());
}
/**
* Registers a flag for use in plots.
*
* @param flag the flag to register
*
*/
public void addFlag(Flag<?> flag) {
Flags.registerFlag(flag);
}
/**
* Gets a plot based on the ID.
*
* @param world the world the plot is located in
* @param x The PlotID x coordinate
* @param z The PlotID y coordinate
*
* @return plot, null if ID is wrong
*
* @see PlotArea#getPlot(PlotId)
*/
@SuppressWarnings("deprecation")
@Deprecated
public Plot getPlot(World world, int x, int z) {
if (world == null) {
return null;
}
PlotArea area = getWorldSettings(world);
if (area == null) {
return null;
}
return area.getPlot(new PlotId(x, z));
}
/**
* Get a plot based on the location.
*
* @param location the location to check
*
* @return plot if found, otherwise it creates a temporary plot
*
* @see Plot
*/
public Plot getPlot(Location location) {
if (location == null) {
return null;
}
return BukkitUtil.getLocation(location).getPlot();
}
/**
* Get a plot based on the player location.
*
* @param player the player to check
*
* @return plot if found, otherwise it creates a temporary plot
*
* @see #getPlot(Location)
* @see Plot
*/
public Plot getPlot(Player player) {
return this.getPlot(player.getLocation());
}
/**
* Check whether or not a player has a plot.
*
* @param player Player that you want to check for
* @param world The world to check
* @return true if player has a plot, false if not.
*
* @see #getPlots(World, Player, boolean)
*/
@SuppressWarnings("deprecation")
@Deprecated
public boolean hasPlot(World world, Player player) {
return getPlots(world, player, true).length > 0;
}
/**
* Get all plots for the player.
*
* @param world The world to retrieve plots from
* @param player The player to search for
* @param justOwner should we just search for owner? Or with rights?
* @return An array of plots for the player
*/
@Deprecated
public Plot[] getPlots(World world, Player player, boolean justOwner) {
ArrayList<Plot> pPlots = new ArrayList<>();
UUID uuid = BukkitUtil.getPlayer(player).getUUID();
for (Plot plot : PS.get().getPlots(world.getName())) {
if (justOwner) {
if (plot.hasOwner() && plot.isOwner(uuid)) {
pPlots.add(plot);
}
} else if (plot.isAdded(uuid)) {
pPlots.add(plot);
}
}
return pPlots.toArray(new Plot[pPlots.size()]);
}
/**
* Get all plots for the world.
*
* @param world to get plots of
*
* @return Plot[] - array of plot objects in world
*
* @see PS#getPlots(String)
* @see Plot
*/
@Deprecated
public Plot[] getPlots(World world) {
if (world == null) {
return new Plot[0];
}
Collection<Plot> plots = PS.get().getPlots(world.getName());
return plots.toArray(new Plot[plots.size()]);
}
/**
* Get all plot worlds.
*
* @return World[] - array of plot worlds
*
*/
@SuppressWarnings("deprecation")
@Deprecated
public String[] getPlotWorlds() {
Set<String> plotWorldStrings = PS.get().getPlotWorldStrings();
return plotWorldStrings.toArray(new String[plotWorldStrings.size()]);
}
/**
* Get if plotworld.
*
* @param world The world to check
*
* @return boolean (if plot world or not)
*
* @see PS#hasPlotArea(String)
*/
@Deprecated
public boolean isPlotWorld(World world) {
return PS.get().hasPlotArea(world.getName());
}
/**
* Get plot locations.
*
* @param plot Plot to get the locations for
*
* @return [0] = bottomLc, [1] = topLoc, [2] = home
*
* @deprecated As merged plots may not have a rectangular shape
*
* @see Plot
*/
@SuppressWarnings("deprecation")
@Deprecated
public Location[] getLocations(Plot plot) {
Location bukkitBottom = BukkitUtil.getLocation(plot.getCorners()[0]);
Location bukkitTop = BukkitUtil.getLocation(plot.getCorners()[1]);
Location bukkitHome = BukkitUtil.getLocation(plot.getHome());
return new Location[]{bukkitBottom, bukkitTop, bukkitHome};
}
/**
* Get home location.
*
* @param plot Plot that you want to get the location for
*
* @return plot bottom location
*
* @see Plot
*/
public Location getHomeLocation(Plot plot) {
return BukkitUtil.getLocation(plot.getHome());
}
/**
* Get Bottom Location (min, min, min).
*
* @param plot Plot that you want to get the location for
*
* @return plot bottom location
*
* @deprecated As merged plots may not have a rectangular shape
*
* @see Plot
*/
@SuppressWarnings("deprecation")
@Deprecated
public Location getBottomLocation(Plot plot) {
return BukkitUtil.getLocation(plot.getCorners()[0]);
}
/**
* Get Top Location (max, max, max).
*
* @param plot Plot that you want to get the location for
*
* @return plot top location
*
* @deprecated As merged plots may not have a rectangular shape
*
* @see Plot
*/
@SuppressWarnings("deprecation")
@Deprecated
public Location getTopLocation(Plot plot) {
return BukkitUtil.getLocation(plot.getCorners()[1]);
}
/**
* Check whether or not a player is in a plot.
*
* @param player who we're checking for
*
* @return true if the player is in a plot, false if not-
*
*/
public boolean isInPlot(Player player) {
return getPlot(player) != null;
}
/**
* Register a subcommand.
* @deprecated Command registration is done on object creation
* @param c SubCommand, that we want to register
* @see SubCommand
*/
@Deprecated
public void registerCommand(SubCommand c) {
PS.debug("SubCommands are now registered on creation");
}
/**
* Gets the PlotSquared class.
*
* @return PlotSquared Class
*
* @see PS
*/
public PS getPlotSquared() {
return PS.get();
}
/**
* Gets the player plot count.
*
* @param world Specify the world we want to select the plots from
* @param player Player, for whom we're getting the plot count
*
* @return the number of plots the player has
*
*/
public int getPlayerPlotCount(World world, Player player) {
if (world == null) {
return 0;
}
return BukkitUtil.getPlayer(player).getPlotCount(world.getName());
}
/**
* Gets a collection containing the players plots.
*
* @param world Specify the world we want to select the plots from
* @param player Player, for whom we're getting the plots
*
* @return a set containing the players plots
*
* @see PS#getPlots(String, PlotPlayer)
*
* @see Plot
*/
public Set<Plot> getPlayerPlots(World world, Player player) {
if (world == null) {
return new HashSet<>();
}
return PlotPlayer.wrap(player).getPlots(world.getName());
}
/**
* Gets the number of plots, which the player is able to build in.
*
* @param player player, for whom we're getting the plots
*
* @return the number of allowed plots
*
*/
public int getAllowedPlots(Player player) {
PlotPlayer plotPlayer = PlotPlayer.wrap(player);
return plotPlayer.getAllowedPlots();
}
/**
* Gets the PlotPlayer for a player. The PlotPlayer is usually cached and
* will provide useful functions relating to players.
*
* @see PlotPlayer#wrap(Object)
*
* @param player the player to wrap
* @return a {@code PlotPlayer}
*/
public PlotPlayer wrapPlayer(Player player) {
return PlotPlayer.wrap(player);
}
/**
* Get the PlotPlayer for a UUID.
*
* <p><i>Please note that PlotSquared can be configured to provide
* different UUIDs than bukkit</i>
*
* @see PlotPlayer#wrap(Object)
*
* @param uuid the uuid of the player to wrap
* @return a {@code PlotPlayer}
*/
public PlotPlayer wrapPlayer(UUID uuid) {
return PlotPlayer.wrap(uuid);
}
/**
* Get the PlotPlayer for a username.
*
* @see PlotPlayer#wrap(Object)
*
* @param player the player to wrap
* @return a {@code PlotPlayer}
*/
public PlotPlayer wrapPlayer(String player) {
return PlotPlayer.wrap(player);
}
/**
* Get the PlotPlayer for an offline player.
*
* <p>Note that this will work if the player is offline, however not all
* functionality will work.
*
* @see PlotPlayer#wrap(Object)
*
* @param player the player to wrap
* @return a {@code PlotPlayer}
*/
public PlotPlayer wrapPlayer(OfflinePlayer player) {
return PlotPlayer.wrap(player);
}
}

View File

@ -0,0 +1,805 @@
package com.plotsquared.bukkit;
import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.plot.IPlotMain;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.ConfigurationNode;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.generator.GeneratorWrapper;
import com.intellectualcrafters.plot.generator.HybridGen;
import com.intellectualcrafters.plot.generator.HybridUtils;
import com.intellectualcrafters.plot.generator.IndependentPlotGenerator;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.object.RunnableVal;
import com.intellectualcrafters.plot.object.SetupObject;
import com.intellectualcrafters.plot.object.chat.PlainChatManager;
import com.intellectualcrafters.plot.object.worlds.PlotAreaManager;
import com.intellectualcrafters.plot.object.worlds.SinglePlotArea;
import com.intellectualcrafters.plot.object.worlds.SinglePlotAreaManager;
import com.intellectualcrafters.plot.object.worlds.SingleWorldGenerator;
import com.intellectualcrafters.plot.util.AbstractTitle;
import com.intellectualcrafters.plot.util.ChatManager;
import com.intellectualcrafters.plot.util.ChunkManager;
import com.intellectualcrafters.plot.util.ConsoleColors;
import com.intellectualcrafters.plot.util.EconHandler;
import com.intellectualcrafters.plot.util.EventUtil;
import com.intellectualcrafters.plot.util.InventoryUtil;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.SchematicHandler;
import com.intellectualcrafters.plot.util.SetupUtils;
import com.intellectualcrafters.plot.util.StringMan;
import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.UUIDHandler;
import com.intellectualcrafters.plot.util.UUIDHandlerImplementation;
import com.intellectualcrafters.plot.util.WorldUtil;
import com.intellectualcrafters.plot.util.block.QueueProvider;
import com.intellectualcrafters.plot.uuid.UUIDWrapper;
import com.plotsquared.bukkit.database.plotme.ClassicPlotMeConnector;
import com.plotsquared.bukkit.database.plotme.LikePlotMeConverter;
import com.plotsquared.bukkit.database.plotme.PlotMeConnector_017;
import com.plotsquared.bukkit.generator.BukkitPlotGenerator;
import com.plotsquared.bukkit.listeners.ChunkListener;
import com.plotsquared.bukkit.listeners.EntitySpawnListener;
import com.plotsquared.bukkit.listeners.PlayerEvents;
import com.plotsquared.bukkit.listeners.PlayerEvents183;
import com.plotsquared.bukkit.listeners.PlayerEvents_1_8;
import com.plotsquared.bukkit.listeners.PlayerEvents_1_9;
import com.plotsquared.bukkit.listeners.PlotPlusListener;
import com.plotsquared.bukkit.listeners.WorldEvents;
import com.plotsquared.bukkit.titles.DefaultTitle_111;
import com.plotsquared.bukkit.util.BukkitChatManager;
import com.plotsquared.bukkit.util.BukkitChunkManager;
import com.plotsquared.bukkit.util.BukkitCommand;
import com.plotsquared.bukkit.util.BukkitEconHandler;
import com.plotsquared.bukkit.util.BukkitEventUtil;
import com.plotsquared.bukkit.util.BukkitHybridUtils;
import com.plotsquared.bukkit.util.BukkitInventoryUtil;
import com.plotsquared.bukkit.util.BukkitSchematicHandler;
import com.plotsquared.bukkit.util.BukkitSetupUtils;
import com.plotsquared.bukkit.util.BukkitTaskManager;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.bukkit.util.BukkitVersion;
import com.plotsquared.bukkit.util.Metrics;
import com.plotsquared.bukkit.util.SendChunk;
import com.plotsquared.bukkit.util.SetGenCB;
import com.plotsquared.bukkit.util.block.BukkitLocalQueue;
import com.plotsquared.bukkit.util.block.BukkitLocalQueue_1_7;
import com.plotsquared.bukkit.util.block.BukkitLocalQueue_1_8;
import com.plotsquared.bukkit.util.block.BukkitLocalQueue_1_8_3;
import com.plotsquared.bukkit.util.block.BukkitLocalQueue_1_9;
import com.plotsquared.bukkit.uuid.DefaultUUIDWrapper;
import com.plotsquared.bukkit.uuid.FileUUIDHandler;
import com.plotsquared.bukkit.uuid.LowerOfflineUUIDWrapper;
import com.plotsquared.bukkit.uuid.OfflineUUIDWrapper;
import com.plotsquared.bukkit.uuid.SQLUUIDHandler;
import com.sk89q.worldedit.WorldEdit;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain {
private static ConcurrentHashMap<String, Plugin> pluginMap;
static {
// Disable AWE as otherwise both fail to load
PluginManager manager = Bukkit.getPluginManager();
try {
Settings.load(new File("plugins/PlotSquared/config/settings.yml"));
if (Settings.Enabled_Components.PLOTME_CONVERTER) { // Only disable PlotMe if conversion is enabled
Field pluginsField = manager.getClass().getDeclaredField("plugins");
Field lookupNamesField = manager.getClass().getDeclaredField("lookupNames");
pluginsField.setAccessible(true);
lookupNamesField.setAccessible(true);
List<Plugin> plugins = (List<Plugin>) pluginsField.get(manager);
Iterator<Plugin> iter = plugins.iterator();
while (iter.hasNext()) {
if (iter.next().getName().startsWith("PlotMe")) {
iter.remove();
}
}
Map<String, Plugin> lookupNames = (Map<String, Plugin>) lookupNamesField.get(manager);
lookupNames.remove("PlotMe");
lookupNames.remove("PlotMe-DefaultGenerator");
pluginsField.set(manager, new ArrayList<Plugin>(plugins) {
@Override
public boolean add(Plugin plugin) {
if (plugin.getName().startsWith("PlotMe")) {
System.out.print("Disabling `" + plugin.getName() + "` for PlotMe conversion (configure in PlotSquared settings.yml)");
} else {
return super.add(plugin);
}
return false;
}
});
pluginMap = new ConcurrentHashMap<String, Plugin>(lookupNames) {
@Override
public Plugin put(String key, Plugin plugin) {
if (!plugin.getName().startsWith("PlotMe")) {
return super.put(key, plugin);
}
return null;
}
};
lookupNamesField.set(manager, pluginMap);
}
} catch (Throwable ignore) {}
}
public static WorldEdit worldEdit;
private int[] version;
private String name;
@Override
public int[] getServerVersion() {
if (this.version == null) {
try {
this.version = new int[3];
String[] split = Bukkit.getBukkitVersion().split("-")[0].split("\\.");
this.version[0] = Integer.parseInt(split[0]);
this.version[1] = Integer.parseInt(split[1]);
if (split.length == 3) {
this.version[2] = Integer.parseInt(split[2]);
}
} catch (NumberFormatException e) {
e.printStackTrace();
PS.debug(StringMan.getString(Bukkit.getBukkitVersion()));
PS.debug(StringMan.getString(Bukkit.getBukkitVersion().split("-")[0].split("\\.")));
return new int[]{1, 10, 0};
}
}
return this.version;
}
@Override
public void onEnable() {
if (pluginMap != null) {
pluginMap.put("PlotMe-DefaultGenerator", this);
}
this.name = getDescription().getName();
getServer().getName();
new PS(this, "Bukkit");
if (Settings.Enabled_Components.METRICS) {
new Metrics(this).start();
PS.log(C.PREFIX + "&6Metrics enabled.");
} else {
PS.log(C.CONSOLE_PLEASE_ENABLE_METRICS.f(getPluginName()));
}
if (Settings.Enabled_Components.WORLDS) {
TaskManager.IMP.taskRepeat(new Runnable() {
@Override
public void run() {
unload();
}
}, 20);
}
}
public void unload() {
PlotAreaManager manager = PS.get().getPlotAreaManager();
if (manager instanceof SinglePlotAreaManager) {
long start = System.currentTimeMillis();
SinglePlotArea area = ((SinglePlotAreaManager) manager).getArea();
for (World world : Bukkit.getWorlds()) {
String name = world.getName();
PlotId id = PlotId.fromString(name);
if (id != null) {
Plot plot = area.getOwnedPlot(id);
if (plot != null) {
List<PlotPlayer> players = plot.getPlayersInPlot();
if (players.isEmpty() && PlotPlayer.wrap(plot.owner) == null) {
for (Chunk chunk : world.getLoadedChunks()) {
chunk.unload(true, false);
if (System.currentTimeMillis() - start > 20) {
return;
}
}
Bukkit.unloadWorld(world, false);
}
}
}
}
}
}
@Override
public void onDisable() {
PS.get().disable();
Bukkit.getScheduler().cancelTasks(this);
}
@Override
public void log(String message) {
try {
message = C.color(message);
if (!Settings.Chat.CONSOLE_COLOR) {
message = ChatColor.stripColor(message);
}
this.getServer().getConsoleSender().sendMessage(message);
} catch (Throwable ignored) {
System.out.println(ConsoleColors.fromString(message));
}
}
@Override
public void disable() {
onDisable();
}
@Override
public int[] getPluginVersion() {
String ver = getDescription().getVersion();
if (ver.contains("-")) {
ver = ver.split("-")[0];
}
String[] split = ver.split("\\.");
return new int[]{Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])};
}
@Override public String getPluginVersionString() {
return getDescription().getVersion();
}
@Override
public String getPluginName() {
return name;
}
@Override
public void registerCommands() {
BukkitCommand bukkitCommand = new BukkitCommand();
PluginCommand plotCommand = getCommand("plots");
plotCommand.setExecutor(bukkitCommand);
plotCommand.setAliases(Arrays.asList("p", "ps", "plotme", "plot"));
plotCommand.setTabCompleter(bukkitCommand);
}
@Override
public File getDirectory() {
return getDataFolder();
}
@Override
public File getWorldContainer() {
return Bukkit.getWorldContainer();
}
@Override
public TaskManager getTaskManager() {
return new BukkitTaskManager(this);
}
@Override
public void runEntityTask() {
PS.log(C.PREFIX + "KillAllEntities started.");
TaskManager.runTaskRepeat(new Runnable() {
@Override
public void run() {
PS.get().foreachPlotArea(new RunnableVal<PlotArea>() {
@Override
public void run(PlotArea plotArea) {
World world = Bukkit.getWorld(plotArea.worldname);
try {
if (world == null) {
return;
}
List<Entity> entities = world.getEntities();
Iterator<Entity> iterator = entities.iterator();
while (iterator.hasNext()) {
Entity entity = iterator.next();
switch (entity.getType()) {
case EGG:
case COMPLEX_PART:
case FISHING_HOOK:
case ENDER_SIGNAL:
case LINGERING_POTION:
case AREA_EFFECT_CLOUD:
case EXPERIENCE_ORB:
case LEASH_HITCH:
case FIREWORK:
case WEATHER:
case LIGHTNING:
case WITHER_SKULL:
case UNKNOWN:
case PLAYER:
// non moving / unmovable
continue;
case THROWN_EXP_BOTTLE:
case SPLASH_POTION:
case SNOWBALL:
case SHULKER_BULLET:
case SPECTRAL_ARROW:
case TIPPED_ARROW:
case ENDER_PEARL:
case ARROW:
case LLAMA_SPIT:
// managed elsewhere | projectile
continue;
case ITEM_FRAME:
case PAINTING:
// Not vehicles
continue;
case ARMOR_STAND:
// Temporarily classify as vehicle
case MINECART:
case MINECART_CHEST:
case MINECART_COMMAND:
case MINECART_FURNACE:
case MINECART_HOPPER:
case MINECART_MOB_SPAWNER:
case ENDER_CRYSTAL:
case MINECART_TNT:
case BOAT:
if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) {
com.intellectualcrafters.plot.object.Location location = BukkitUtil.getLocation(entity.getLocation());
Plot plot = location.getPlot();
if (plot == null) {
if (location.isPlotArea()) {
iterator.remove();
entity.remove();
}
continue;
}
List<MetadataValue> meta = entity.getMetadata("plot");
if (meta.isEmpty()) {
continue;
}
Plot origin = (Plot) meta.get(0).value();
if (!plot.equals(origin.getBasePlot(false))) {
iterator.remove();
entity.remove();
}
continue;
} else {
continue;
}
case SMALL_FIREBALL:
case FIREBALL:
case DRAGON_FIREBALL:
case DROPPED_ITEM:
// dropped item
continue;
case PRIMED_TNT:
case FALLING_BLOCK:
// managed elsewhere
continue;
case LLAMA:
case DONKEY:
case MULE:
case ZOMBIE_HORSE:
case SKELETON_HORSE:
case HUSK:
case ELDER_GUARDIAN:
case WITHER_SKELETON:
case STRAY:
case ZOMBIE_VILLAGER:
case EVOKER:
case EVOKER_FANGS:
case VEX:
case VINDICATOR:
case POLAR_BEAR:
case BAT:
case BLAZE:
case CAVE_SPIDER:
case CHICKEN:
case COW:
case CREEPER:
case ENDERMAN:
case ENDERMITE:
case ENDER_DRAGON:
case GHAST:
case GIANT:
case GUARDIAN:
case HORSE:
case IRON_GOLEM:
case MAGMA_CUBE:
case MUSHROOM_COW:
case OCELOT:
case PIG:
case PIG_ZOMBIE:
case RABBIT:
case SHEEP:
case SILVERFISH:
case SKELETON:
case SLIME:
case SNOWMAN:
case SPIDER:
case SQUID:
case VILLAGER:
case WITCH:
case WITHER:
case WOLF:
case ZOMBIE:
case SHULKER:
default:
if (Settings.Enabled_Components.KILL_ROAD_MOBS) {
Location location = entity.getLocation();
if (BukkitUtil.getLocation(location).isPlotRoad()) {
if (entity instanceof LivingEntity) {
LivingEntity livingEntity = (LivingEntity) entity;
if (!livingEntity.isLeashed() || !entity.hasMetadata("keep")) {
Entity passenger = entity.getPassenger();
if (!(passenger instanceof Player) && entity.getMetadata("keep").isEmpty()) {
iterator.remove();
entity.remove();
}
}
} else {
Entity passenger = entity.getPassenger();
if (!(passenger instanceof Player) && entity.getMetadata("keep").isEmpty()) {
iterator.remove();
entity.remove();
}
}
}
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
});
}
}, 20);
}
@Override
public final ChunkGenerator getDefaultWorldGenerator(String world, String id) {
if (Settings.Enabled_Components.PLOTME_CONVERTER) {
initPlotMeConverter();
Settings.Enabled_Components.PLOTME_CONVERTER = false;
}
IndependentPlotGenerator result;
if (id != null && id.equalsIgnoreCase("single")) {
result = new SingleWorldGenerator();
} else {
result = PS.get().IMP.getDefaultGenerator();
if (!PS.get().setupPlotWorld(world, id, result)) {
return null;
}
}
return (ChunkGenerator) result.specify(world);
}
@Override
public void registerPlayerEvents() {
PlayerEvents main = new PlayerEvents();
getServer().getPluginManager().registerEvents(main, this);
try {
getServer().getClass().getMethod("spigot");
Class.forName("org.bukkit.event.entity.EntitySpawnEvent");
getServer().getPluginManager().registerEvents(new EntitySpawnListener(), this);
} catch (NoSuchMethodException | ClassNotFoundException ignored) {
PS.debug("Not running Spigot. Skipping EntitySpawnListener event.");
}
if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_8_0)) {
try {
getServer().getPluginManager().registerEvents(new PlayerEvents_1_8(), this);
} catch (Throwable e) {
e.printStackTrace();
}
}
if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_8_3)) {
try {
getServer().getPluginManager().registerEvents(new PlayerEvents183(), this);
} catch (Throwable e) {
e.printStackTrace();
}
}
if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_9_0)) {
try {
getServer().getPluginManager().registerEvents(new PlayerEvents_1_9(main), this);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
@Override
public void registerInventoryEvents() {
// Part of PlayerEvents - can be moved if necessary
}
@Override
public void registerPlotPlusEvents() {
PlotPlusListener.startRunnable(this);
getServer().getPluginManager().registerEvents(new PlotPlusListener(), this);
}
@Override
public void registerForceFieldEvents() {
}
@Override
public boolean initWorldEdit() {
if (getServer().getPluginManager().getPlugin("WorldEdit") != null) {
worldEdit = WorldEdit.getInstance();
return true;
}
return false;
}
@Override
public EconHandler getEconomyHandler() {
try {
BukkitEconHandler econ = new BukkitEconHandler();
if (econ.init()) {
return econ;
}
} catch (Throwable ignored) {
PS.debug("No economy detected!");
}
return null;
}
@Override
public QueueProvider initBlockQueue() {
try {
new SendChunk();
MainUtil.canSendChunk = true;
} catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) {
PS.debug(SendChunk.class + " does not support " + StringMan.getString(getServerVersion()));
MainUtil.canSendChunk = false;
}
if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_9_0)) {
return QueueProvider.of(BukkitLocalQueue_1_9.class, BukkitLocalQueue.class);
}
if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_8_3)) {
return QueueProvider.of(BukkitLocalQueue_1_8_3.class, BukkitLocalQueue.class);
}
if (PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_8_0)) {
return QueueProvider.of(BukkitLocalQueue_1_8.class, BukkitLocalQueue.class);
}
return QueueProvider.of(BukkitLocalQueue_1_7.class, BukkitLocalQueue.class);
}
@Override
public WorldUtil initWorldUtil() {
return new BukkitUtil();
}
@Override
public boolean initPlotMeConverter() {
if (new LikePlotMeConverter("PlotMe").run(new ClassicPlotMeConnector())) {
return true;
} else if (new LikePlotMeConverter("PlotMe").run(new PlotMeConnector_017())) {
return true;
}
return false;
}
@Override
public GeneratorWrapper<?> getGenerator(String world, String name) {
if (name == null) {
return null;
}
Plugin genPlugin = Bukkit.getPluginManager().getPlugin(name);
if (genPlugin != null && genPlugin.isEnabled()) {
ChunkGenerator gen = genPlugin.getDefaultWorldGenerator(world, "");
if (gen instanceof GeneratorWrapper<?>) {
return (GeneratorWrapper<?>) gen;
}
return new BukkitPlotGenerator(world, gen);
} else {
return new BukkitPlotGenerator(PS.get().IMP.getDefaultGenerator());
}
}
@Override
public HybridUtils initHybridUtils() {
return new BukkitHybridUtils();
}
@Override
public SetupUtils initSetupUtils() {
return new BukkitSetupUtils();
}
@Override
public UUIDHandlerImplementation initUUIDHandler() {
boolean checkVersion = PS.get().checkVersion(getServerVersion(), BukkitVersion.v1_7_6);
UUIDWrapper wrapper;
if (Settings.UUID.OFFLINE) {
if (Settings.UUID.FORCE_LOWERCASE) {
wrapper = new LowerOfflineUUIDWrapper();
} else {
wrapper = new OfflineUUIDWrapper();
}
Settings.UUID.OFFLINE = true;
} else if (checkVersion) {
wrapper = new DefaultUUIDWrapper();
Settings.UUID.OFFLINE = false;
} else {
if (Settings.UUID.FORCE_LOWERCASE) {
wrapper = new LowerOfflineUUIDWrapper();
} else {
wrapper = new OfflineUUIDWrapper();
}
Settings.UUID.OFFLINE = true;
}
if (!checkVersion) {
PS.log(C.PREFIX + " &c[WARN] Titles are disabled - please update your version of Bukkit to support this feature.");
Settings.TITLES = false;
} else {
AbstractTitle.TITLE_CLASS = new DefaultTitle_111();
if (wrapper instanceof DefaultUUIDWrapper || wrapper.getClass() == OfflineUUIDWrapper.class && !Bukkit.getOnlineMode()) {
Settings.UUID.NATIVE_UUID_PROVIDER = true;
}
}
if (Settings.UUID.OFFLINE) {
PS.log(C.PREFIX
+ " &6" + getPluginName() + " is using Offline Mode UUIDs either because of user preference, or because you are using an old version of "
+ "Bukkit");
} else {
PS.log(C.PREFIX + " &6" + getPluginName() + " is using online UUIDs");
}
if (Settings.UUID.USE_SQLUUIDHANDLER) {
return new SQLUUIDHandler(wrapper);
} else {
return new FileUUIDHandler(wrapper);
}
}
@Override
public ChunkManager initChunkManager() {
return new BukkitChunkManager();
}
@Override
public EventUtil initEventUtil() {
return new BukkitEventUtil();
}
@Override
public void unregister(PlotPlayer player) {
BukkitUtil.removePlayer(player.getName());
}
@Override
public void registerChunkProcessor() {
getServer().getPluginManager().registerEvents(new ChunkListener(), this);
}
@Override
public void registerWorldEvents() {
getServer().getPluginManager().registerEvents(new WorldEvents(), this);
}
@Override
public IndependentPlotGenerator getDefaultGenerator() {
return new HybridGen();
}
@Override
public InventoryUtil initInventoryUtil() {
return new BukkitInventoryUtil();
}
@Override
public void startMetrics() {
new Metrics(this).start();
PS.log(C.PREFIX + "&6Metrics enabled.");
}
@Override
public void setGenerator(String worldName) {
World world = BukkitUtil.getWorld(worldName);
if (world == null) {
// create world
ConfigurationSection worldConfig = PS.get().worlds.getConfigurationSection("worlds." + worldName);
String manager = worldConfig.getString("generator.plugin", getPluginName());
SetupObject setup = new SetupObject();
setup.plotManager = manager;
setup.setupGenerator = worldConfig.getString("generator.init", manager);
setup.type = worldConfig.getInt("generator.type");
setup.terrain = worldConfig.getInt("generator.terrain");
setup.step = new ConfigurationNode[0];
setup.world = worldName;
SetupUtils.manager.setupWorld(setup);
world = Bukkit.getWorld(worldName);
} else {
try {
if (!PS.get().hasPlotArea(worldName)) {
SetGenCB.setGenerator(BukkitUtil.getWorld(worldName));
}
} catch (Exception ignored) {
PS.log("Failed to reload world: " + world + " | " + ignored.getMessage());
Bukkit.getServer().unloadWorld(world, false);
return;
}
}
ChunkGenerator gen = world.getGenerator();
if (gen instanceof BukkitPlotGenerator) {
PS.get().loadWorld(worldName, (BukkitPlotGenerator) gen);
} else if (gen != null) {
PS.get().loadWorld(worldName, new BukkitPlotGenerator(worldName, gen));
} else if (PS.get().worlds.contains("worlds." + worldName)) {
PS.get().loadWorld(worldName, null);
}
}
@Override
public SchematicHandler initSchematicHandler() {
return new BukkitSchematicHandler();
}
@Override
public AbstractTitle initTitleManager() {
// Already initialized in UUID handler
return AbstractTitle.TITLE_CLASS;
}
@Override
public PlotPlayer wrapPlayer(Object player) {
if (player instanceof Player) {
return BukkitUtil.getPlayer((Player) player);
}
if (player instanceof OfflinePlayer) {
return BukkitUtil.getPlayer((OfflinePlayer) player);
}
if (player instanceof String) {
return UUIDHandler.getPlayer((String) player);
}
if (player instanceof UUID) {
return UUIDHandler.getPlayer((UUID) player);
}
return null;
}
@Override
public String getNMSPackage() {
String name = Bukkit.getServer().getClass().getPackage().getName();
return name.substring(name.lastIndexOf('.') + 1);
}
@Override
public ChatManager<?> initChatManager() {
if (Settings.Chat.INTERACTIVE) {
return new BukkitChatManager();
} else {
return new PlainChatManager();
}
}
@Override
public GeneratorWrapper<?> wrapPlotGenerator(String world, IndependentPlotGenerator generator) {
return new BukkitPlotGenerator(generator);
}
@Override
public List<String> getPluginIds() {
ArrayList<String> names = new ArrayList<>();
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
names.add(plugin.getName() + ';' + plugin.getDescription().getVersion() + ':' + plugin.isEnabled());
}
return names;
}
}

View File

@ -1,28 +1,30 @@
package com.plotsquared.bukkit.chat; package com.plotsquared.bukkit.chat;
import org.apache.commons.lang.Validate;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import org.apache.commons.lang.Validate;
/** /**
* Represents a wrapper around an array class of an arbitrary reference type, * Represents a wrapper around an array class of an arbitrary reference type,
* which properly implements "value" hash code and equality functions. * which properly implements "value" hash code and equality functions.
* <p> * <p>
* This class is intended for use as a key to a map. * This class is intended for use as a key to a map.
* </p> * </p>
* @author Glen Husman *
* @param <E> The type of elements in the array. * @param <E> The type of elements in the array.
* @author Glen Husman
* @see Arrays * @see Arrays
*/ */
public final class ArrayWrapper<E> { public final class ArrayWrapper<E> {
/** /**
* Creates an array wrapper with some elements. * Creates an array wrapper with some elements.
*
* @param elements The elements of the array. * @param elements The elements of the array.
*/ */
public ArrayWrapper(final E... elements) { public ArrayWrapper(E... elements) {
setArray(elements); setArray(elements);
} }
@ -30,6 +32,7 @@ public final class ArrayWrapper<E> {
/** /**
* Retrieves a reference to the wrapped array instance. * Retrieves a reference to the wrapped array instance.
*
* @return The array wrapped by this instance. * @return The array wrapped by this instance.
*/ */
public E[] getArray() { public E[] getArray() {
@ -38,20 +41,22 @@ public final class ArrayWrapper<E> {
/** /**
* Set this wrapper to wrap a new array instance. * Set this wrapper to wrap a new array instance.
*
* @param array The new wrapped array. * @param array The new wrapped array.
*/ */
public void setArray(final E[] array) { public void setArray(E[] array) {
Validate.notNull(array, "The array must not be null."); Validate.notNull(array, "The array must not be null.");
_array = array; _array = array;
} }
/** /**
* Determines if this object has a value equivalent to another object. * Determines if this object has a value equivalent to another object.
*
* @see Arrays#equals(Object[], Object[]) * @see Arrays#equals(Object[], Object[])
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Override @Override
public boolean equals(final Object other) { public boolean equals(Object other) {
if (!(other instanceof ArrayWrapper)) { if (!(other instanceof ArrayWrapper)) {
return false; return false;
} }
@ -60,8 +65,9 @@ public final class ArrayWrapper<E> {
/** /**
* Gets the hash code represented by this objects value. * Gets the hash code represented by this objects value.
* @see Arrays#hashCode(Object[]) *
* @return This object's hash code. * @return This object's hash code.
* @see Arrays#hashCode(Object[])
*/ */
@Override @Override
public int hashCode() { public int hashCode() {
@ -71,33 +77,35 @@ public final class ArrayWrapper<E> {
/** /**
* Converts an iterable element collection to an array of elements. * Converts an iterable element collection to an array of elements.
* The iteration order of the specified object will be used as the array element order. * The iteration order of the specified object will be used as the array element order.
*
* @param list The iterable of objects which will be converted to an array. * @param list The iterable of objects which will be converted to an array.
* @param c The type of the elements of the array. * @param c The type of the elements of the array.
* @return An array of elements in the specified iterable. * @return An array of elements in the specified iterable.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T[] toArray(final Iterable<? extends T> list, final Class<T> c) { public static <T> T[] toArray(Iterable<? extends T> list, Class<T> c) {
int size = -1; int size = -1;
if (list instanceof Collection<?>) { if (list instanceof Collection<?>) {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
final Collection coll = (Collection) list; Collection coll = (Collection) list;
size = coll.size(); size = coll.size();
} }
if (size < 0) { if (size < 0) {
size = 0; size = 0;
// Ugly hack: Count it ourselves // Ugly hack: Count it ourselves
for (@SuppressWarnings("unused") for (@SuppressWarnings("unused") T element : list) {
final T element : list) {
size++; size++;
} }
} }
final T[] result = (T[]) Array.newInstance(c, size); T[] result = (T[]) Array.newInstance(c, size);
int i = 0; int i = 0;
for (final T element : list) { // Assumes iteration order is consistent for (T element : list) { // Assumes iteration order is consistent
result[i++] = element; // Assign array element at index THEN increment counter result[i++] = element; // Assign array element at index THEN increment counter
} }
return result; return result;
} }
} }

View File

@ -7,8 +7,6 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
import org.bukkit.Achievement; import org.bukkit.Achievement;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -16,6 +14,8 @@ import org.bukkit.Material;
import org.bukkit.Statistic; import org.bukkit.Statistic;
import org.bukkit.Statistic.Type; import org.bukkit.Statistic.Type;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -29,7 +29,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -42,7 +41,7 @@ import java.util.logging.Level;
* <p> * <p>
* This class follows the builder pattern, allowing for method chaining. * This class follows the builder pattern, allowing for method chaining.
* It is set up such that invocations of property-setting methods will affect the current editing component, * It is set up such that invocations of property-setting methods will affect the current editing component,
* and a call to {@link #then(String)} or {@link #text(TextualComponent)} will append a new editing component to the end of the message, * and a call to {@link #then()} or {@link #then(String)} will append a new editing component to the end of the message,
* optionally initializing it with text. Further property-setting method calls will affect that editing component. * optionally initializing it with text. Further property-setting method calls will affect that editing component.
* </p> * </p>
*/ */
@ -60,7 +59,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
@Override @Override
public FancyMessage clone() throws CloneNotSupportedException { public FancyMessage clone() throws CloneNotSupportedException {
final FancyMessage instance = (FancyMessage) super.clone(); FancyMessage instance = (FancyMessage) super.clone();
instance.messageParts = new ArrayList<>(messageParts.size()); instance.messageParts = new ArrayList<>(messageParts.size());
for (int i = 0; i < messageParts.size(); i++) { for (int i = 0; i < messageParts.size(); i++) {
instance.messageParts.add(i, messageParts.get(i).clone()); instance.messageParts.add(i, messageParts.get(i).clone());
@ -72,25 +71,25 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Creates a JSON message with text. * Creates a JSON message with text.
*
* @param firstPartText The existing text in the message. * @param firstPartText The existing text in the message.
*/ */
public FancyMessage(final String firstPartText) { public FancyMessage(final String firstPartText) {
this(rawText(firstPartText)); this(rawText(firstPartText));
} }
public FancyMessage(final TextualComponent firstPartText) { private FancyMessage(final TextualComponent firstPartText) {
messageParts = new ArrayList<>(); messageParts = new ArrayList<>();
messageParts.add(new MessagePart(firstPartText)); messageParts.add(new MessagePart(firstPartText));
jsonString = null; jsonString = null;
dirty = false; dirty = false;
if (nmsPacketPlayOutChatConstructor == null) { if (nmsPacketPlayOutChatConstructor == null) {
try { try {
nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat").getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent")); nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat").getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent"));
nmsPacketPlayOutChatConstructor.setAccessible(true); nmsPacketPlayOutChatConstructor.setAccessible(true);
} catch (final NoSuchMethodException e) { } catch (NoSuchMethodException e) {
Bukkit.getLogger().log(Level.SEVERE, "Could not find Minecraft method or constructor.", e); Bukkit.getLogger().log(Level.SEVERE, "Could not find Minecraft method or constructor.", e);
} catch (final SecurityException e) { } catch (SecurityException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e); Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e);
} }
} }
@ -105,11 +104,12 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Sets the text of the current editing component to a value. * Sets the text of the current editing component to a value.
*
* @param text The new text of the current editing component. * @param text The new text of the current editing component.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage text(final String text) { public FancyMessage text(String text) {
final MessagePart latest = latest(); MessagePart latest = latest();
latest.text = rawText(text); latest.text = rawText(text);
dirty = true; dirty = true;
return this; return this;
@ -117,11 +117,12 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Sets the text of the current editing component to a value. * Sets the text of the current editing component to a value.
*
* @param text The new text of the current editing component. * @param text The new text of the current editing component.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage text(final TextualComponent text) { public FancyMessage text(TextualComponent text) {
final MessagePart latest = latest(); MessagePart latest = latest();
latest.text = text; latest.text = text;
dirty = true; dirty = true;
return this; return this;
@ -129,11 +130,15 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Sets the color of the current editing component to a value. * Sets the color of the current editing component to a value.
*
* @param color The new color of the current editing component. * @param color The new color of the current editing component.
* @return This builder instance. * @return This builder instance.
* @exception IllegalArgumentException If the specified {@code ChatColor} enumeration value is not a color (but a format value). * @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not a color (but a format value).
*/ */
public FancyMessage color(final ChatColor color) { public FancyMessage color(final ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color; latest().color = color;
dirty = true; dirty = true;
return this; return this;
@ -141,11 +146,12 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Sets the stylization of the current editing component. * Sets the stylization of the current editing component.
*
* @param styles The array of styles to apply to the editing component. * @param styles The array of styles to apply to the editing component.
* @return This builder instance. * @return This builder instance.
* @exception IllegalArgumentException If any of the enumeration values in the array do not represent formatters. * @throws IllegalArgumentException If any of the enumeration values in the array do not represent formatters.
*/ */
public FancyMessage style(final ChatColor... styles) { public FancyMessage style(ChatColor... styles) {
for (final ChatColor style : styles) { for (final ChatColor style : styles) {
if (!style.isFormat()) { if (!style.isFormat()) {
throw new IllegalArgumentException(style.name() + " is not a style"); throw new IllegalArgumentException(style.name() + " is not a style");
@ -158,6 +164,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to instruct the client to open a file on the client side filesystem when the currently edited part of the {@code FancyMessage} is clicked. * Set the behavior of the current editing component to instruct the client to open a file on the client side filesystem when the currently edited part of the {@code FancyMessage} is clicked.
*
* @param path The path of the file on the client filesystem. * @param path The path of the file on the client filesystem.
* @return This builder instance. * @return This builder instance.
*/ */
@ -168,6 +175,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to instruct the client to open a webpage in the client's web browser when the currently edited part of the {@code FancyMessage} is clicked. * Set the behavior of the current editing component to instruct the client to open a webpage in the client's web browser when the currently edited part of the {@code FancyMessage} is clicked.
*
* @param url The URL of the page to open when the link is clicked. * @param url The URL of the page to open when the link is clicked.
* @return This builder instance. * @return This builder instance.
*/ */
@ -179,6 +187,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to instruct the client to replace the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is clicked. * Set the behavior of the current editing component to instruct the client to replace the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is clicked.
* The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key. * The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key.
*
* @param command The text to display in the chat bar of the client. * @param command The text to display in the chat bar of the client.
* @return This builder instance. * @return This builder instance.
*/ */
@ -190,6 +199,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to instruct the client to append the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is SHIFT-CLICKED. * Set the behavior of the current editing component to instruct the client to append the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is SHIFT-CLICKED.
* The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key. * The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key.
*
* @param command The text to append to the chat bar of the client. * @param command The text to append to the chat bar of the client.
* @return This builder instance. * @return This builder instance.
*/ */
@ -202,6 +212,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to instruct the client to send the specified string to the server as a chat message when the currently edited part of the {@code FancyMessage} is clicked. * Set the behavior of the current editing component to instruct the client to send the specified string to the server as a chat message when the currently edited part of the {@code FancyMessage} is clicked.
* The client <b>will</b> immediately send the command to the server to be executed when the editing component is clicked. * The client <b>will</b> immediately send the command to the server to be executed when the editing component is clicked.
*
* @param command The text to display in the chat bar of the client. * @param command The text to display in the chat bar of the client.
* @return This builder instance. * @return This builder instance.
*/ */
@ -213,6 +224,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display information about an achievement when the client hovers over the text. * Set the behavior of the current editing component to display information about an achievement when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param name The name of the achievement to display, excluding the "achievement." prefix. * @param name The name of the achievement to display, excluding the "achievement." prefix.
* @return This builder instance. * @return This builder instance.
*/ */
@ -224,20 +236,21 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display information about an achievement when the client hovers over the text. * Set the behavior of the current editing component to display information about an achievement when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param which The achievement to display. * @param which The achievement to display.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage achievementTooltip(final Achievement which) { public FancyMessage achievementTooltip(final Achievement which) {
try { try {
final Object achievement = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSAchievement", Achievement.class).invoke(null, which); Object achievement = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSAchievement", Achievement.class).invoke(null, which);
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Achievement"), "name").get(achievement)); return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Achievement"), "name").get(achievement));
} catch (final IllegalAccessException e) { } catch (IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
return this; return this;
} catch (final IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
return this; return this;
} catch (final InvocationTargetException e) { } catch (InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
return this; return this;
} }
@ -246,25 +259,26 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display information about a parameterless statistic when the client hovers over the text. * Set the behavior of the current editing component to display information about a parameterless statistic when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param which The statistic to display. * @param which The statistic to display.
* @return This builder instance. * @return This builder instance.
* @exception IllegalArgumentException If the statistic requires a parameter which was not supplied. * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied.
*/ */
public FancyMessage statisticTooltip(final Statistic which) { public FancyMessage statisticTooltip(final Statistic which) {
final Type type = which.getType(); Type type = which.getType();
if (type != Type.UNTYPED) { if (type != Type.UNTYPED) {
throw new IllegalArgumentException("That statistic requires an additional " + type + " parameter!"); throw new IllegalArgumentException("That statistic requires an additional " + type + " parameter!");
} }
try { try {
final Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSStatistic", Statistic.class).invoke(null, which); Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSStatistic", Statistic.class).invoke(null, which);
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
} catch (final IllegalAccessException e) { } catch (IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
return this; return this;
} catch (final IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
return this; return this;
} catch (final InvocationTargetException e) { } catch (InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
return this; return this;
} }
@ -273,29 +287,30 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display information about a statistic parameter with a material when the client hovers over the text. * Set the behavior of the current editing component to display information about a statistic parameter with a material when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param which The statistic to display. * @param which The statistic to display.
* @param item The sole material parameter to the statistic. * @param item The sole material parameter to the statistic.
* @return This builder instance. * @return This builder instance.
* @exception IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required. * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required.
*/ */
public FancyMessage statisticTooltip(final Statistic which, final Material item) { public FancyMessage statisticTooltip(final Statistic which, Material item) {
final Type type = which.getType(); Type type = which.getType();
if (type == Type.UNTYPED) { if (type == Type.UNTYPED) {
throw new IllegalArgumentException("That statistic needs no additional parameter!"); throw new IllegalArgumentException("That statistic needs no additional parameter!");
} }
if (((type == Type.BLOCK) && item.isBlock()) || (type == Type.ENTITY)) { if ((type == Type.BLOCK && item.isBlock()) || type == Type.ENTITY) {
throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!"); throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!");
} }
try { try {
final Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getMaterialStatistic", Statistic.class, Material.class).invoke(null, which, item); Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getMaterialStatistic", Statistic.class, Material.class).invoke(null, which, item);
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
} catch (final IllegalAccessException e) { } catch (IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
return this; return this;
} catch (final IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
return this; return this;
} catch (final InvocationTargetException e) { } catch (InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
return this; return this;
} }
@ -304,13 +319,14 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display information about a statistic parameter with an entity type when the client hovers over the text. * Set the behavior of the current editing component to display information about a statistic parameter with an entity type when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param which The statistic to display. * @param which The statistic to display.
* @param entity The sole entity type parameter to the statistic. * @param entity The sole entity type parameter to the statistic.
* @return This builder instance. * @return This builder instance.
* @exception IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required. * @throws IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required.
*/ */
public FancyMessage statisticTooltip(final Statistic which, final EntityType entity) { public FancyMessage statisticTooltip(final Statistic which, EntityType entity) {
final Type type = which.getType(); Type type = which.getType();
if (type == Type.UNTYPED) { if (type == Type.UNTYPED) {
throw new IllegalArgumentException("That statistic needs no additional parameter!"); throw new IllegalArgumentException("That statistic needs no additional parameter!");
} }
@ -318,15 +334,15 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!"); throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!");
} }
try { try {
final Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getEntityStatistic", Statistic.class, EntityType.class).invoke(null, which, entity); Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getEntityStatistic", Statistic.class, EntityType.class).invoke(null, which, entity);
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic)); return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
} catch (final IllegalAccessException e) { } catch (IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
return this; return this;
} catch (final IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
return this; return this;
} catch (final InvocationTargetException e) { } catch (InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
return this; return this;
} }
@ -335,6 +351,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display information about an item when the client hovers over the text. * Set the behavior of the current editing component to display information about an item when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param itemJSON A string representing the JSON-serialized NBT data tag of an {@link ItemStack}. * @param itemJSON A string representing the JSON-serialized NBT data tag of an {@link ItemStack}.
* @return This builder instance. * @return This builder instance.
*/ */
@ -346,15 +363,15 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display information about an item when the client hovers over the text. * Set the behavior of the current editing component to display information about an item when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param itemStack The stack for which to display information. * @param itemStack The stack for which to display information.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage itemTooltip(final ItemStack itemStack) { public FancyMessage itemTooltip(final ItemStack itemStack) {
try { try {
final Object nmsItem = Reflection.getMethod(Reflection.getOBCClass("inventory.CraftItemStack"), "asNMSCopy", ItemStack.class).invoke(null, itemStack); Object nmsItem = Reflection.getMethod(Reflection.getOBCClass("inventory.CraftItemStack"), "asNMSCopy", ItemStack.class).invoke(null, itemStack);
return itemTooltip(Reflection.getMethod(Reflection.getNMSClass("ItemStack"), "save", Reflection.getNMSClass("NBTTagCompound")) return itemTooltip(Reflection.getMethod(Reflection.getNMSClass("ItemStack"), "save", Reflection.getNMSClass("NBTTagCompound")).invoke(nmsItem, Reflection.getNMSClass("NBTTagCompound").newInstance()).toString());
.invoke(nmsItem, Reflection.getNMSClass("NBTTagCompound").newInstance()).toString()); } catch (Exception e) {
} catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
return this; return this;
} }
@ -363,6 +380,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display raw text when the client hovers over the text. * Set the behavior of the current editing component to display raw text when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param text The text, which supports newlines, which will be displayed to the client upon hovering. * @param text The text, which supports newlines, which will be displayed to the client upon hovering.
* @return This builder instance. * @return This builder instance.
*/ */
@ -374,25 +392,27 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display raw text when the client hovers over the text. * Set the behavior of the current editing component to display raw text when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created. * @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage tooltip(final Iterable<String> lines) { public FancyMessage tooltip(final Iterable<String> lines) {
tooltip(ArrayWrapper.toArray(lines, String.class)); tooltip(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, String.class));
return this; return this;
} }
/** /**
* Set the behavior of the current editing component to display raw text when the client hovers over the text. * Set the behavior of the current editing component to display raw text when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param lines The lines of text which will be displayed to the client upon hovering. * @param lines The lines of text which will be displayed to the client upon hovering.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage tooltip(final String... lines) { public FancyMessage tooltip(final String... lines) {
final StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
builder.append(lines[i]); builder.append(lines[i]);
if (i != (lines.length - 1)) { if (i != lines.length - 1) {
builder.append('\n'); builder.append('\n');
} }
} }
@ -403,14 +423,15 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display formatted text when the client hovers over the text. * Set the behavior of the current editing component to display formatted text when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param text The formatted text which will be displayed to the client upon hovering. * @param text The formatted text which will be displayed to the client upon hovering.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage formattedTooltip(final FancyMessage text) { public FancyMessage formattedTooltip(FancyMessage text) {
for (final MessagePart component : text.messageParts) { for (MessagePart component : text.messageParts) {
if ((component.clickActionData != null) && (component.clickActionName != null)) { if (component.clickActionData != null && component.clickActionName != null) {
throw new IllegalArgumentException("The tooltip text cannot have click data."); throw new IllegalArgumentException("The tooltip text cannot have click data.");
} else if ((component.hoverActionData != null) && (component.hoverActionName != null)) { } else if (component.hoverActionData != null && component.hoverActionName != null) {
throw new IllegalArgumentException("The tooltip text cannot have a tooltip."); throw new IllegalArgumentException("The tooltip text cannot have a tooltip.");
} }
} }
@ -421,34 +442,35 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text. * Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param lines The lines of formatted text which will be displayed to the client upon hovering. * @param lines The lines of formatted text which will be displayed to the client upon hovering.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage formattedTooltip(final FancyMessage... lines) { public FancyMessage formattedTooltip(FancyMessage... lines) {
if (lines.length < 1) { if (lines.length < 1) {
onHover(null, null); // Clear tooltip onHover(null, null); // Clear tooltip
return this; return this;
} }
final FancyMessage result = new FancyMessage(); FancyMessage result = new FancyMessage();
result.messageParts.clear(); // Remove the one existing text component that exists by default, which destabilizes the object result.messageParts.clear(); // Remove the one existing text component that exists by default, which destabilizes the object
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
try { try {
for (final MessagePart component : lines[i]) { for (MessagePart component : lines[i]) {
if ((component.clickActionData != null) && (component.clickActionName != null)) { if (component.clickActionData != null && component.clickActionName != null) {
throw new IllegalArgumentException("The tooltip text cannot have click data."); throw new IllegalArgumentException("The tooltip text cannot have click data.");
} else if ((component.hoverActionData != null) && (component.hoverActionName != null)) { } else if (component.hoverActionData != null && component.hoverActionName != null) {
throw new IllegalArgumentException("The tooltip text cannot have a tooltip."); throw new IllegalArgumentException("The tooltip text cannot have a tooltip.");
} }
if (component.hasText()) { if (component.hasText()) {
result.messageParts.add(component.clone()); result.messageParts.add(component.clone());
} }
} }
if (i != (lines.length - 1)) { if (i != lines.length - 1) {
result.messageParts.add(new MessagePart(rawText("\n"))); result.messageParts.add(new MessagePart(rawText("\n")));
} }
} catch (final CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to clone object", e); Bukkit.getLogger().log(Level.WARNING, "Failed to clone object", e);
return this; return this;
} }
@ -459,27 +481,28 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text. * Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text.
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p> * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
*
* @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created. * @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage formattedTooltip(final Iterable<FancyMessage> lines) { public FancyMessage formattedTooltip(final Iterable<FancyMessage> lines) {
return formattedTooltip(ArrayWrapper.toArray(lines, FancyMessage.class)); return formattedTooltip(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, FancyMessage.class));
} }
/** /**
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
*
* @param replacements The replacements, in order, that will be used in the language-specific message. * @param replacements The replacements, in order, that will be used in the language-specific message.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage translationReplacements(final String... replacements) { public FancyMessage translationReplacements(final String... replacements) {
for (final String str : replacements) { for (String str : replacements) {
latest().translationReplacements.add(new JsonString(str)); latest().translationReplacements.add(new JsonString(str));
} }
dirty = true; dirty = true;
return this; return this;
} }
/* /*
/** /**
@ -499,11 +522,14 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
*
* @param replacements The replacements, in order, that will be used in the language-specific message. * @param replacements The replacements, in order, that will be used in the language-specific message.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage translationReplacements(final FancyMessage... replacements) { public FancyMessage translationReplacements(final FancyMessage... replacements) {
Collections.addAll(latest().translationReplacements, replacements); for (FancyMessage str : replacements) {
latest().translationReplacements.add(str);
}
dirty = true; dirty = true;
@ -512,16 +538,18 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message. * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
*
* @param replacements The replacements, in order, that will be used in the language-specific message. * @param replacements The replacements, in order, that will be used in the language-specific message.
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage translationReplacements(final Iterable<FancyMessage> replacements) { public FancyMessage translationReplacements(final Iterable<FancyMessage> replacements) {
return translationReplacements(ArrayWrapper.toArray(replacements, FancyMessage.class)); return translationReplacements(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(replacements, FancyMessage.class));
} }
/** /**
* Terminate construction of the current editing component, and begin construction of a new message component. * Terminate construction of the current editing component, and begin construction of a new message component.
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method.
*
* @param text The text which will populate the new message component. * @param text The text which will populate the new message component.
* @return This builder instance. * @return This builder instance.
*/ */
@ -532,6 +560,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Terminate construction of the current editing component, and begin construction of a new message component. * Terminate construction of the current editing component, and begin construction of a new message component.
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method.
*
* @param text The text which will populate the new message component. * @param text The text which will populate the new message component.
* @return This builder instance. * @return This builder instance.
*/ */
@ -547,6 +576,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Terminate construction of the current editing component, and begin construction of a new message component. * Terminate construction of the current editing component, and begin construction of a new message component.
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method. * After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method.
*
* @return This builder instance. * @return This builder instance.
*/ */
public FancyMessage then() { public FancyMessage then() {
@ -559,7 +589,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
@Override @Override
public void writeJson(final JsonWriter writer) throws IOException { public void writeJson(JsonWriter writer) throws IOException {
if (messageParts.size() == 1) { if (messageParts.size() == 1) {
latest().writeJson(writer); latest().writeJson(writer);
} else { } else {
@ -574,18 +604,19 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Serialize this fancy message, converting it into syntactically-valid JSON using a {@link JsonWriter}. * Serialize this fancy message, converting it into syntactically-valid JSON using a {@link JsonWriter}.
* This JSON should be compatible with vanilla formatter commands such as {@code /tellraw}. * This JSON should be compatible with vanilla formatter commands such as {@code /tellraw}.
*
* @return The JSON string representing this object. * @return The JSON string representing this object.
*/ */
public String toJSONString() { public String toJSONString() {
if (!dirty && (jsonString != null)) { if (!dirty && jsonString != null) {
return jsonString; return jsonString;
} }
final StringWriter string = new StringWriter(); StringWriter string = new StringWriter();
final JsonWriter json = new JsonWriter(string); JsonWriter json = new JsonWriter(string);
try { try {
writeJson(json); writeJson(json);
json.close(); json.close();
} catch (final IOException e) { } catch (IOException e) {
throw new RuntimeException("invalid message"); throw new RuntimeException("invalid message");
} }
jsonString = string.toString(); jsonString = string.toString();
@ -595,33 +626,34 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* Sends this message to a player. The player will receive the fully-fledged formatted display of this message. * Sends this message to a player. The player will receive the fully-fledged formatted display of this message.
*
* @param player The player who will receive the message. * @param player The player who will receive the message.
*/ */
public void send(final Player player) { public void send(Player player) {
send(player, toJSONString()); send(player, toJSONString());
} }
private void send(final CommandSender sender, final String jsonString) { private void send(CommandSender sender, String jsonString) {
if (!(sender instanceof Player)) { if (!(sender instanceof Player)) {
sender.sendMessage(toOldMessageFormat()); sender.sendMessage(toOldMessageFormat());
return; return;
} }
final Player player = (Player) sender; Player player = (Player) sender;
try { try {
final Object handle = Reflection.getHandle(player); Object handle = Reflection.getHandle(player);
final Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle); Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle);
Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, createChatPacket(jsonString)); Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, createChatPacket(jsonString));
} catch (final IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
} catch (final IllegalAccessException e) { } catch (IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
} catch (final InstantiationException e) { } catch (InstantiationException e) {
Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e); Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e);
} catch (final InvocationTargetException e) { } catch (InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e); Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
} catch (final NoSuchMethodException e) { } catch (NoSuchMethodException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e); Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e);
} catch (final ClassNotFoundException e) { } catch (ClassNotFoundException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e); Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e);
} }
} }
@ -630,17 +662,23 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
private static Object nmsChatSerializerGsonInstance; private static Object nmsChatSerializerGsonInstance;
private static Method fromJsonMethod; private static Method fromJsonMethod;
private Object createChatPacket(final String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, private Object createChatPacket(String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
ClassNotFoundException {
if (nmsChatSerializerGsonInstance == null) { if (nmsChatSerializerGsonInstance == null) {
// Find the field and its value, completely bypassing obfuscation // Find the field and its value, completely bypassing obfuscation
Class<?> chatSerializerClazz; Class<?> chatSerializerClazz;
// Get the three parts of the version string (major version is currently unused)
// vX_Y_RZ
// X = major
// Y = minor
// Z = revision
final String version = Reflection.getVersion(); final String version = Reflection.getVersion();
final double majorVersion = Double.parseDouble(version.replace('_', '.').substring(1, 4)); String[] split = version.substring(1, version.length() - 1).split("_"); // Remove trailing dot
final int lesserVersion = Integer.parseInt(version.substring(6, 7)); //int majorVersion = Integer.parseInt(split[0]);
int minorVersion = Integer.parseInt(split[1]);
int revisionVersion = Integer.parseInt(split[2].substring(1)); // Substring to ignore R
if ((majorVersion < 1.8) || ((majorVersion == 1.8) && (lesserVersion == 1))) { if (minorVersion < 8 || (minorVersion == 8 && revisionVersion == 1)) {
chatSerializerClazz = Reflection.getNMSClass("ChatSerializer"); chatSerializerClazz = Reflection.getNMSClass("ChatSerializer");
} else { } else {
chatSerializerClazz = Reflection.getNMSClass("IChatBaseComponent$ChatSerializer"); chatSerializerClazz = Reflection.getNMSClass("IChatBaseComponent$ChatSerializer");
@ -650,7 +688,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
throw new ClassNotFoundException("Can't find the ChatSerializer class"); throw new ClassNotFoundException("Can't find the ChatSerializer class");
} }
for (final Field declaredField : chatSerializerClazz.getDeclaredFields()) { for (Field declaredField : chatSerializerClazz.getDeclaredFields()) {
if (Modifier.isFinal(declaredField.getModifiers()) && Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().getName().endsWith("Gson")) { if (Modifier.isFinal(declaredField.getModifiers()) && Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().getName().endsWith("Gson")) {
// We've found our field // We've found our field
declaredField.setAccessible(true); declaredField.setAccessible(true);
@ -661,12 +699,9 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
} }
/* // Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' than to reflectively call it
Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' // Of course, the implementation may change, but fuzzy matches might break with signature changes
than to reflectively call it Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, Reflection.getNMSClass("IChatBaseComponent"));
Of course, the implementation may change, but fuzzy matches might break with signature changes
*/
final Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, Reflection.getNMSClass("IChatBaseComponent"));
return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent); return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent);
} }
@ -675,20 +710,22 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
* Sends this message to a command sender. * Sends this message to a command sender.
* If the sender is a player, they will receive the fully-fledged formatted display of this message. * If the sender is a player, they will receive the fully-fledged formatted display of this message.
* Otherwise, they will receive a version of this message with less formatting. * Otherwise, they will receive a version of this message with less formatting.
*
* @param sender The command sender who will receive the message. * @param sender The command sender who will receive the message.
* @see #toOldMessageFormat() * @see #toOldMessageFormat()
*/ */
public void send(final CommandSender sender) { public void send(CommandSender sender) {
send(sender, toJSONString()); send(sender, toJSONString());
} }
/** /**
* Sends this message to multiple command senders. * Sends this message to multiple command senders.
*
* @param senders The command senders who will receive the message. * @param senders The command senders who will receive the message.
* @see #send(CommandSender) * @see #send(CommandSender)
*/ */
public void send(final Iterable<? extends CommandSender> senders) { public void send(final Iterable<? extends CommandSender> senders) {
final String string = toJSONString(); String string = toJSONString();
for (final CommandSender sender : senders) { for (final CommandSender sender : senders) {
send(sender, string); send(sender, string);
} }
@ -701,20 +738,21 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
* Serialization of this message by using this message will include (in this order for each message part): * Serialization of this message by using this message will include (in this order for each message part):
* <ol> * <ol>
* <li>The color of each message part.</li> * <li>The color of each message part.</li>
* <li>The applicable stylization for each message part.</li> * <li>The applicable stylizations for each message part.</li>
* <li>The core text of the message part.</li> * <li>The core text of the message part.</li>
* </ol> * </ol>
* The primary omissions are tooltips and clickable actions. Consequently, this method should be used only as a last resort. * The primary omissions are tooltips and clickable actions. Consequently, this method should be used only as a last resort.
* </p> * </p>
* <p> * <p>
* Color and formatting can be removed from the returned string by using {@link ChatColor#stripColor(String)}.</p> * Color and formatting can be removed from the returned string by using {@link ChatColor#stripColor(String)}.</p>
*
* @return A human-readable string representing limited formatting in addition to the core text of this message. * @return A human-readable string representing limited formatting in addition to the core text of this message.
*/ */
public String toOldMessageFormat() { public String toOldMessageFormat() {
final StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
for (final MessagePart part : this) { for (MessagePart part : this) {
result.append(part.color == null ? "" : part.color); result.append(part.color == null ? "" : part.color);
for (final ChatColor formatSpecifier : part.styles) { for (ChatColor formatSpecifier : part.styles) {
result.append(formatSpecifier); result.append(formatSpecifier);
} }
result.append(part.text); result.append(part.text);
@ -741,23 +779,23 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
// Doc copied from interface // Doc copied from interface
@Override
public Map<String, Object> serialize() { public Map<String, Object> serialize() {
final HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
map.put("messageParts", messageParts); map.put("messageParts", messageParts);
// map.put("JSON", toJSONString()); // map.put("JSON", toJSONString());
return map; return map;
} }
/** /**
* Deserialize a JSON-represented message from a mapping of key-value pairs. * Deserializes a JSON-represented message from a mapping of key-value pairs.
* This is called by the Bukkit serialization API. * This is called by the Bukkit serialization API.
* It is not intended for direct public API consumption. * It is not intended for direct public API consumption.
*
* @param serialized The key-value mapping which represents a fancy message. * @param serialized The key-value mapping which represents a fancy message.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static FancyMessage deserialize(final Map<String, Object> serialized) { public static FancyMessage deserialize(Map<String, Object> serialized) {
final FancyMessage msg = new FancyMessage(); FancyMessage msg = new FancyMessage();
msg.messageParts = (List<MessagePart>) serialized.get("messageParts"); msg.messageParts = (List<MessagePart>) serialized.get("messageParts");
msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null; msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null;
msg.dirty = !serialized.containsKey("JSON"); msg.dirty = !serialized.containsKey("JSON");
@ -767,7 +805,6 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
/** /**
* <b>Internally called method. Not for API consumption.</b> * <b>Internally called method. Not for API consumption.</b>
*/ */
@Override
public Iterator<MessagePart> iterator() { public Iterator<MessagePart> iterator() {
return messageParts.iterator(); return messageParts.iterator();
} }
@ -775,31 +812,32 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
private static JsonParser _stringParser = new JsonParser(); private static JsonParser _stringParser = new JsonParser();
/** /**
* Deserialize a fancy message from its JSON representation. This JSON representation is of the format of * Deserializes a fancy message from its JSON representation. This JSON representation is of the format of
* that returned by {@link #toJSONString()}, and is compatible with vanilla inputs. * that returned by {@link #toJSONString()}, and is compatible with vanilla inputs.
*
* @param json The JSON string which represents a fancy message. * @param json The JSON string which represents a fancy message.
* @return A {@code FancyMessage} representing the parametrized JSON message. * @return A {@code FancyMessage} representing the parameterized JSON message.
*/ */
public static FancyMessage deserialize(final String json) { public static FancyMessage deserialize(String json) {
final JsonObject serialized = _stringParser.parse(json).getAsJsonObject(); JsonObject serialized = _stringParser.parse(json).getAsJsonObject();
final JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component
final FancyMessage returnVal = new FancyMessage(); FancyMessage returnVal = new FancyMessage();
returnVal.messageParts.clear(); returnVal.messageParts.clear();
for (final JsonElement mPrt : extra) { for (JsonElement mPrt : extra) {
final MessagePart component = new MessagePart(); MessagePart component = new MessagePart();
final JsonObject messagePart = mPrt.getAsJsonObject(); JsonObject messagePart = mPrt.getAsJsonObject();
for (final Map.Entry<String, JsonElement> entry : messagePart.entrySet()) { for (Map.Entry<String, JsonElement> entry : messagePart.entrySet()) {
// Deserialize text // Deserialize text
if (TextualComponent.isTextKey(entry.getKey())) { if (TextualComponent.isTextKey(entry.getKey())) {
// The map mimics the YAML serialization, which has a "key" field and one or more "value" fields // The map mimics the YAML serialization, which has a "key" field and one or more "value" fields
final Map<String, Object> serializedMapForm = new HashMap<>(); // Must be object due to Bukkit serializer API compliance Map<String, Object> serializedMapForm = new HashMap<>(); // Must be object due to Bukkit serializer API compliance
serializedMapForm.put("key", entry.getKey()); serializedMapForm.put("key", entry.getKey());
if (entry.getValue().isJsonPrimitive()) { if (entry.getValue().isJsonPrimitive()) {
// Assume string // Assume string
serializedMapForm.put("value", entry.getValue().getAsString()); serializedMapForm.put("value", entry.getValue().getAsString());
} else { } else {
// Composite object, but we assume each element is a string // Composite object, but we assume each element is a string
for (final Map.Entry<String, JsonElement> compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()) { for (Map.Entry<String, JsonElement> compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()) {
serializedMapForm.put("value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString()); serializedMapForm.put("value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString());
} }
} }
@ -811,11 +849,11 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} else if (entry.getKey().equals("color")) { } else if (entry.getKey().equals("color")) {
component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase()); component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase());
} else if (entry.getKey().equals("clickEvent")) { } else if (entry.getKey().equals("clickEvent")) {
final JsonObject object = entry.getValue().getAsJsonObject(); JsonObject object = entry.getValue().getAsJsonObject();
component.clickActionName = object.get("action").getAsString(); component.clickActionName = object.get("action").getAsString();
component.clickActionData = object.get("value").getAsString(); component.clickActionData = object.get("value").getAsString();
} else if (entry.getKey().equals("hoverEvent")) { } else if (entry.getKey().equals("hoverEvent")) {
final JsonObject object = entry.getValue().getAsJsonObject(); JsonObject object = entry.getValue().getAsJsonObject();
component.hoverActionName = object.get("action").getAsString(); component.hoverActionName = object.get("action").getAsString();
if (object.get("value").isJsonPrimitive()) { if (object.get("value").isJsonPrimitive()) {
// Assume string // Assume string
@ -829,7 +867,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} else if (entry.getKey().equals("insertion")) { } else if (entry.getKey().equals("insertion")) {
component.insertionData = entry.getValue().getAsString(); component.insertionData = entry.getValue().getAsString();
} else if (entry.getKey().equals("with")) { } else if (entry.getKey().equals("with")) {
for (final JsonElement object : entry.getValue().getAsJsonArray()) { for (JsonElement object : entry.getValue().getAsJsonArray()) {
if (object.isJsonPrimitive()) { if (object.isJsonPrimitive()) {
component.translationReplacements.add(new JsonString(object.getAsString())); component.translationReplacements.add(new JsonString(object.getAsString()));
} else { } else {
@ -844,4 +882,5 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
} }
return returnVal; return returnVal;
} }
} }

View File

@ -1,9 +1,9 @@
package com.plotsquared.bukkit.chat; package com.plotsquared.bukkit.chat;
import java.io.IOException;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException;
/** /**
* Represents an object that can be serialized to a JSON writer instance. * Represents an object that can be serialized to a JSON writer instance.
*/ */
@ -14,6 +14,6 @@ interface JsonRepresentedObject {
* @param writer The JSON writer which will receive the object. * @param writer The JSON writer which will receive the object.
* @throws IOException If an error occurs writing to the stream. * @throws IOException If an error occurs writing to the stream.
*/ */
void writeJson(final JsonWriter writer) throws IOException; public void writeJson(JsonWriter writer) throws IOException;
} }

View File

@ -1,12 +1,12 @@
package com.plotsquared.bukkit.chat; package com.plotsquared.bukkit.chat;
import com.google.gson.stream.JsonWriter;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.google.gson.stream.JsonWriter;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
/** /**
* Represents a JSON string value. * Represents a JSON string value.
* Writes by this object will not write name values nor begin/end objects in the JSON stream. * Writes by this object will not write name values nor begin/end objects in the JSON stream.
@ -14,14 +14,14 @@ import com.intellectualcrafters.configuration.serialization.ConfigurationSeriali
*/ */
final class JsonString implements JsonRepresentedObject, ConfigurationSerializable { final class JsonString implements JsonRepresentedObject, ConfigurationSerializable {
private final String _value; private String _value;
public JsonString(final CharSequence value) { public JsonString(CharSequence value) {
_value = value == null ? null : value.toString(); _value = value == null ? null : value.toString();
} }
@Override @Override
public void writeJson(final JsonWriter writer) throws IOException { public void writeJson(JsonWriter writer) throws IOException {
writer.value(getValue()); writer.value(getValue());
} }
@ -29,14 +29,13 @@ final class JsonString implements JsonRepresentedObject, ConfigurationSerializab
return _value; return _value;
} }
@Override
public Map<String, Object> serialize() { public Map<String, Object> serialize() {
final HashMap<String, Object> theSingleValue = new HashMap<String, Object>(); HashMap<String, Object> theSingleValue = new HashMap<String, Object>();
theSingleValue.put("stringValue", _value); theSingleValue.put("stringValue", _value);
return theSingleValue; return theSingleValue;
} }
public static JsonString deserialize(final Map<String, Object> map) { public static JsonString deserialize(Map<String, Object> map) {
return new JsonString(map.get("stringValue").toString()); return new JsonString(map.get("stringValue").toString());
} }
@ -44,4 +43,5 @@ final class JsonString implements JsonRepresentedObject, ConfigurationSerializab
public String toString() { public String toString() {
return _value; return _value;
} }
} }

View File

@ -3,10 +3,10 @@ package com.plotsquared.bukkit.chat;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableBiMap;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -19,10 +19,47 @@ import java.util.logging.Level;
*/ */
final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable { final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable {
ChatColor color = ChatColor.WHITE;
ArrayList<ChatColor> styles = new ArrayList<>();
String clickActionName = null;
String clickActionData = null;
String hoverActionName = null;
JsonRepresentedObject hoverActionData = null;
TextualComponent text = null;
String insertionData = null;
ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<>();
MessagePart(final TextualComponent text) {
this.text = text;
}
MessagePart() {
this.text = null;
}
boolean hasText() {
return text != null;
}
@Override
@SuppressWarnings("unchecked")
public MessagePart clone() throws CloneNotSupportedException {
MessagePart obj = (MessagePart) super.clone();
obj.styles = (ArrayList<ChatColor>) styles.clone();
if (hoverActionData instanceof JsonString) {
obj.hoverActionData = new JsonString(((JsonString) hoverActionData).getValue());
} else if (hoverActionData instanceof FancyMessage) {
obj.hoverActionData = ((FancyMessage) hoverActionData).clone();
}
obj.translationReplacements = (ArrayList<JsonRepresentedObject>) translationReplacements.clone();
return obj;
}
static final BiMap<ChatColor, String> stylesToNames; static final BiMap<ChatColor, String> stylesToNames;
static { static {
final ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder(); ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder();
for (final ChatColor style : ChatColor.values()) { for (final ChatColor style : ChatColor.values()) {
if (!style.isFormat()) { if (!style.isFormat()) {
continue; continue;
@ -46,61 +83,7 @@ final class MessagePart implements JsonRepresentedObject, ConfigurationSerializa
stylesToNames = builder.build(); stylesToNames = builder.build();
} }
static { public void writeJson(JsonWriter json) {
ConfigurationSerialization.registerClass(MessagePart.class);
}
ChatColor color = ChatColor.WHITE;
ArrayList<ChatColor> styles = new ArrayList<ChatColor>();
String clickActionName = null, clickActionData = null, hoverActionName = null;
JsonRepresentedObject hoverActionData = null;
TextualComponent text = null;
String insertionData = null;
ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<JsonRepresentedObject>();
MessagePart(final TextualComponent text) {
this.text = text;
}
MessagePart() {
text = null;
}
@SuppressWarnings("unchecked")
public static MessagePart deserialize(final Map<String, Object> serialized) {
final MessagePart part = new MessagePart((TextualComponent) serialized.get("text"));
part.styles = (ArrayList<ChatColor>) serialized.get("styles");
part.color = ChatColor.getByChar(serialized.get("color").toString());
part.hoverActionName = (String) serialized.get("hoverActionName");
part.hoverActionData = (JsonRepresentedObject) serialized.get("hoverActionData");
part.clickActionName = (String) serialized.get("clickActionName");
part.clickActionData = (String) serialized.get("clickActionData");
part.insertionData = (String) serialized.get("insertion");
part.translationReplacements = (ArrayList<JsonRepresentedObject>) serialized.get("translationReplacements");
return part;
}
boolean hasText() {
return text != null;
}
@Override
@SuppressWarnings("unchecked")
public MessagePart clone() throws CloneNotSupportedException {
final MessagePart obj = (MessagePart) super.clone();
obj.styles = (ArrayList<ChatColor>) styles.clone();
if (hoverActionData instanceof JsonString) {
obj.hoverActionData = new JsonString(((JsonString) hoverActionData).getValue());
} else if (hoverActionData instanceof FancyMessage) {
obj.hoverActionData = ((FancyMessage) hoverActionData).clone();
}
obj.translationReplacements = (ArrayList<JsonRepresentedObject>) translationReplacements.clone();
return obj;
}
@Override
public void writeJson(final JsonWriter json) {
try { try {
json.beginObject(); json.beginObject();
text.writeJson(json); text.writeJson(json);
@ -108,33 +91,39 @@ final class MessagePart implements JsonRepresentedObject, ConfigurationSerializa
for (final ChatColor style : styles) { for (final ChatColor style : styles) {
json.name(stylesToNames.get(style)).value(true); json.name(stylesToNames.get(style)).value(true);
} }
if ((clickActionName != null) && (clickActionData != null)) { if (clickActionName != null && clickActionData != null) {
json.name("clickEvent").beginObject().name("action").value(clickActionName).name("value").value(clickActionData).endObject(); json.name("clickEvent")
.beginObject()
.name("action").value(clickActionName)
.name("value").value(clickActionData)
.endObject();
} }
if ((hoverActionName != null) && (hoverActionData != null)) { if (hoverActionName != null && hoverActionData != null) {
json.name("hoverEvent").beginObject().name("action").value(hoverActionName).name("value"); json.name("hoverEvent")
.beginObject()
.name("action").value(hoverActionName)
.name("value");
hoverActionData.writeJson(json); hoverActionData.writeJson(json);
json.endObject(); json.endObject();
} }
if (insertionData != null) { if (insertionData != null) {
json.name("insertion").value(insertionData); json.name("insertion").value(insertionData);
} }
if ((!translationReplacements.isEmpty()) && (text != null) && TextualComponent.isTranslatableText(text)) { if (translationReplacements.size() > 0 && text != null && TextualComponent.isTranslatableText(text)) {
json.name("with").beginArray(); json.name("with").beginArray();
for (final JsonRepresentedObject obj : translationReplacements) { for (JsonRepresentedObject obj : translationReplacements) {
obj.writeJson(json); obj.writeJson(json);
} }
json.endArray(); json.endArray();
} }
json.endObject(); json.endObject();
} catch (final IOException e) { } catch (IOException e) {
Bukkit.getLogger().log(Level.WARNING, "A problem occurred during writing of JSON string", e); Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e);
} }
} }
@Override
public Map<String, Object> serialize() { public Map<String, Object> serialize() {
final HashMap<String, Object> map = new HashMap<String, Object>(); HashMap<String, Object> map = new HashMap<>();
map.put("text", text); map.put("text", text);
map.put("styles", styles); map.put("styles", styles);
map.put("color", color.getChar()); map.put("color", color.getChar());
@ -147,4 +136,22 @@ final class MessagePart implements JsonRepresentedObject, ConfigurationSerializa
return map; return map;
} }
@SuppressWarnings("unchecked")
public static MessagePart deserialize(Map<String, Object> serialized) {
MessagePart part = new MessagePart((TextualComponent) serialized.get("text"));
part.styles = (ArrayList<ChatColor>) serialized.get("styles");
part.color = ChatColor.getByChar(serialized.get("color").toString());
part.hoverActionName = (String) serialized.get("hoverActionName");
part.hoverActionData = (JsonRepresentedObject) serialized.get("hoverActionData");
part.clickActionName = (String) serialized.get("clickActionName");
part.clickActionData = (String) serialized.get("clickActionData");
part.insertionData = (String) serialized.get("insertion");
part.translationReplacements = (ArrayList<JsonRepresentedObject>) serialized.get("translationReplacements");
return part;
}
static {
ConfigurationSerialization.registerClass(MessagePart.class);
}
} }

View File

@ -31,13 +31,12 @@ public final class Reflection {
private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>> _loadedMethods = new HashMap<>(); private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>> _loadedMethods = new HashMap<>();
private static String _versionString; private static String _versionString;
private Reflection() { private Reflection() { }
}
/** /**
* Gets the version string from the package name of the CraftBukkit server implementation. * Gets the version string from the package name of the CraftBukkit server implementation.
* This is needed to bypass the JAR package name changing on each update. * This is needed to bypass the JAR package name changing on each update.
*
* @return The version string of the OBC and NMS packages, <em>including the trailing dot</em>. * @return The version string of the OBC and NMS packages, <em>including the trailing dot</em>.
*/ */
public synchronized static String getVersion() { public synchronized static String getVersion() {
@ -46,7 +45,7 @@ public final class Reflection {
// The server hasn't started, static initializer call? // The server hasn't started, static initializer call?
return null; return null;
} }
final String name = Bukkit.getServer().getClass().getPackage().getName(); String name = Bukkit.getServer().getClass().getPackage().getName();
_versionString = name.substring(name.lastIndexOf('.') + 1) + "."; _versionString = name.substring(name.lastIndexOf('.') + 1) + ".";
} }
@ -56,22 +55,22 @@ public final class Reflection {
/** /**
* Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package. * Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package.
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
*
* @param className The name of the class, excluding the package, within NMS. * @param className The name of the class, excluding the package, within NMS.
* @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded. * @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded.
*/ */
public synchronized static Class<?> getNMSClass(final String className) { public synchronized static Class<?> getNMSClass(String className) {
if (_loadedNMSClasses.containsKey(className)) { if (_loadedNMSClasses.containsKey(className)) {
return _loadedNMSClasses.get(className); return _loadedNMSClasses.get(className);
} }
final String fullName = "net.minecraft.server." + getVersion() + className; String fullName = "net.minecraft.server." + getVersion() + className;
Class<?> clazz; Class<?> clazz;
try { try {
clazz = Class.forName(fullName); clazz = Class.forName(fullName);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
e.printStackTrace();
_loadedNMSClasses.put(className, null); _loadedNMSClasses.put(className, null);
return null; throw new RuntimeException(e);
} }
_loadedNMSClasses.put(className, clazz); _loadedNMSClasses.put(className, clazz);
return clazz; return clazz;
@ -79,25 +78,23 @@ public final class Reflection {
/** /**
* Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package. * Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package.
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
* method simultaneously). *
* @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory * @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}.
* .CraftItemStack}.
* @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded. * @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded.
*/ */
public synchronized static Class<?> getOBCClass(final String className) { public synchronized static Class<?> getOBCClass(String className) {
if (_loadedOBCClasses.containsKey(className)) { if (_loadedOBCClasses.containsKey(className)) {
return _loadedOBCClasses.get(className); return _loadedOBCClasses.get(className);
} }
final String fullName = "org.bukkit.craftbukkit." + getVersion() + className; String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
Class<?> clazz; Class<?> clazz;
try { try {
clazz = Class.forName(fullName); clazz = Class.forName(fullName);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
e.printStackTrace();
_loadedOBCClasses.put(className, null); _loadedOBCClasses.put(className, null);
return null; throw new RuntimeException(e);
} }
_loadedOBCClasses.put(className, clazz); _loadedOBCClasses.put(className, clazz);
return clazz; return clazz;
@ -106,25 +103,14 @@ public final class Reflection {
/** /**
* Attempts to get the NMS handle of a CraftBukkit object. * Attempts to get the NMS handle of a CraftBukkit object.
* <p> * <p>
* The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the * The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object.
* runtime type of the specified object.
* </p> * </p>
*
* @param obj The object for which to retrieve an NMS handle. * @param obj The object for which to retrieve an NMS handle.
* @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}. * @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}.
*/ */
public synchronized static Object getHandle(final Object obj) { public synchronized static Object getHandle(Object obj) throws InvocationTargetException, IllegalAccessException, IllegalArgumentException {
try {
return getMethod(obj.getClass(), "getHandle").invoke(obj); return getMethod(obj.getClass(), "getHandle").invoke(obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
e.printStackTrace();
return null;
}
} }
/** /**
@ -136,16 +122,16 @@ public final class Reflection {
* no field will be reflectively looked up twice. * no field will be reflectively looked up twice.
* </p> * </p>
* <p> * <p>
* If a field is deemed suitable for return, * If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
* {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
* </p> * </p>
*
* @param clazz The class which contains the field to retrieve. * @param clazz The class which contains the field to retrieve.
* @param name The declared name of the field in the class. * @param name The declared name of the field in the class.
* @return A field object with the specified name declared by the specified class. * @return A field object with the specified name declared by the specified class.
* @see Class#getDeclaredField(String) * @see Class#getDeclaredField(String)
*/ */
public synchronized static Field getField(final Class<?> clazz, final String name) { public synchronized static Field getField(Class<?> clazz, String name) {
Map<String, Field> loaded; Map<String, Field> loaded;
if (!_loadedFields.containsKey(clazz)) { if (!_loadedFields.containsKey(clazz)) {
loaded = new HashMap<>(); loaded = new HashMap<>();
@ -158,17 +144,11 @@ public final class Reflection {
return loaded.get(name); return loaded.get(name);
} }
try { try {
final Field field = clazz.getDeclaredField(name); Field field = clazz.getDeclaredField(name);
field.setAccessible(true); field.setAccessible(true);
loaded.put(name, field); loaded.put(name, field);
return field; return field;
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException | SecurityException e) {
// Error loading
e.printStackTrace();
// Cache field as not existing
loaded.put(name, null);
return null;
} catch (SecurityException e) {
// Error loading // Error loading
e.printStackTrace(); e.printStackTrace();
// Cache field as not existing // Cache field as not existing
@ -184,36 +164,35 @@ public final class Reflection {
* <p> * <p>
* A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that * A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that
* no method will be reflectively looked up twice. * no method will be reflectively looked up twice.
* </p>
* <p> * <p>
* If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. * If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
* </p>
* <p> * <p>
* This method does <em>not</em> search superclasses of the specified type for methods with the specified signature. * This method does <em>not</em> search superclasses of the specified type for methods with the specified signature.
* Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}. * Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}.
*
* @param clazz The class which contains the method to retrieve. * @param clazz The class which contains the method to retrieve.
* @param name The declared name of the method in the class. * @param name The declared name of the method in the class.
* @param args The formal argument types of the method. * @param args The formal argument types of the method.
* @return A method object with the specified name declared by the specified class. * @return A method object with the specified name declared by the specified class.
*/ */
public synchronized static Method getMethod(final Class<?> clazz, final String name, final Class<?>... args) { public synchronized static Method getMethod(Class<?> clazz, String name, Class<?>... args) {
if (!_loadedMethods.containsKey(clazz)) { if (!_loadedMethods.containsKey(clazz)) {
_loadedMethods.put(clazz, new HashMap<String, Map<ArrayWrapper<Class<?>>, Method>>()); _loadedMethods.put(clazz, new HashMap<String, Map<ArrayWrapper<Class<?>>, Method>>());
} }
final Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz); Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz);
if (!loadedMethodNames.containsKey(name)) { if (!loadedMethodNames.containsKey(name)) {
loadedMethodNames.put(name, new HashMap<ArrayWrapper<Class<?>>, Method>()); loadedMethodNames.put(name, new HashMap<ArrayWrapper<Class<?>>, Method>());
} }
final Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name); Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name);
final ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<>(args); ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<>(args);
if (loadedSignatures.containsKey(wrappedArg)) { if (loadedSignatures.containsKey(wrappedArg)) {
return loadedSignatures.get(wrappedArg); return loadedSignatures.get(wrappedArg);
} }
for (final Method m : clazz.getMethods()) { for (Method m : clazz.getMethods()) {
if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) { if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) {
m.setAccessible(true); m.setAccessible(true);
loadedSignatures.put(wrappedArg, m); loadedSignatures.put(wrappedArg, m);

View File

@ -3,8 +3,8 @@ package com.plotsquared.bukkit.chat;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerializable;
import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization; import org.bukkit.configuration.serialization.ConfigurationSerialization;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -23,6 +23,119 @@ public abstract class TextualComponent implements Cloneable {
ConfigurationSerialization.registerClass(TextualComponent.ComplexTextTypeComponent.class); ConfigurationSerialization.registerClass(TextualComponent.ComplexTextTypeComponent.class);
} }
static TextualComponent deserialize(Map<String, Object> map) {
if (map.containsKey("key") && map.size() == 2 && map.containsKey("value")) {
// Arbitrary text component
return ArbitraryTextTypeComponent.deserialize(map);
} else if (map.size() >= 2 && map.containsKey("key") && !map.containsKey("value") /* It contains keys that START WITH value */) {
// Complex JSON object
return ComplexTextTypeComponent.deserialize(map);
}
return null;
}
static boolean isTextKey(String key) {
return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector");
}
static boolean isTranslatableText(TextualComponent component) {
return component instanceof ComplexTextTypeComponent && component.getKey().equals("translate");
}
/**
* Create a textual component representing a string literal.
*
* <p>This is the default type of textual component when a single string
* literal is given to a method.
*
* @param textValue The text which will be represented.
* @return The text component representing the specified literal text.
*/
public static TextualComponent rawText(String textValue) {
return new ArbitraryTextTypeComponent("text", textValue);
}
/**
* Create a textual component representing a localized string.
* The client will see this text component as their localized version of the specified string <em>key</em>, which can be overridden by a
* resource pack.
* <p>
* If the specified translation key is not present on the client resource pack, the translation key will be displayed as a string literal to
* the client.
* </p>
*
* @param translateKey The string key which maps to localized text.
* @return The text component representing the specified localized text.
*/
public static TextualComponent localizedText(String translateKey) {
return new ArbitraryTextTypeComponent("translate", translateKey);
}
private static void throwUnsupportedSnapshot() {
throw new UnsupportedOperationException("This feature is only supported in snapshot releases.");
}
/**
* Create a textual component representing a scoreboard value.
* The client will see their own score for the specified objective as the text represented by this component.
* <p>
* <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b>
* </p>
*
* @param scoreboardObjective The name of the objective for which to display the score.
* @return The text component representing the specified scoreboard score (for the viewing player), or {@code null} if an error occurs during
* JSON serialization.
*/
public static TextualComponent objectiveScore(String scoreboardObjective) {
return objectiveScore("*", scoreboardObjective);
}
/**
* Create a textual component representing a scoreboard value.
* The client will see the score of the specified player for the specified objective as the text represented by this component.
*
* <p><b>This method is currently guaranteed to throw an {@code UnsupportedOperationException}
* as it is only supported on snapshot clients.</b>
*
* @param playerName The name of the player whos score will be shown. If
* this string represents the single-character sequence
* "*", the viewing player's score will be displayed.
* Standard minecraft selectors (@a, @p, etc)
* are <em>not</em> supported.
* @param scoreboardObjective The name of the objective for
* which to display the score.
* @return The text component representing the specified scoreboard score
* for the specified player, or {@code null} if an error occurs during JSON serialization.
*/
public static TextualComponent objectiveScore(String playerName, String scoreboardObjective) {
throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE
// OVERLOADS documentation accordingly
return new ComplexTextTypeComponent("score", ImmutableMap.<String, String>builder()
.put("name", playerName)
.put("objective", scoreboardObjective)
.build());
}
/**
* Create a textual component representing a player name, retrievable by using a standard minecraft selector.
* The client will see the players or entities captured by the specified selector as the text represented by this component.
* <p>
* <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b>
* </p>
*
* @param selector The minecraft player or entity selector which will capture the entities whose string representations will be displayed in
* the place of this text component.
* @return The text component representing the name of the entities captured by the selector.
*/
public static TextualComponent selector(String selector) {
throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE
// OVERLOADS documentation accordingly
return new ArbitraryTextTypeComponent("selector", selector);
}
@Override @Override
public String toString() { public String toString() {
return getReadableString(); return getReadableString();
@ -48,30 +161,11 @@ public abstract class TextualComponent implements Cloneable {
/** /**
* Writes the text data represented by this textual component to the specified JSON writer object. * Writes the text data represented by this textual component to the specified JSON writer object.
* A new object within the writer is not started. * A new object within the writer is not started.
*
* @param writer The object to which to write the JSON data. * @param writer The object to which to write the JSON data.
* @throws IOException If an error occurs while writing to the stream. * @throws IOException If an error occurs while writing to the stream.
*/ */
public abstract void writeJson(final JsonWriter writer) throws IOException; public abstract void writeJson(JsonWriter writer) throws IOException;
static TextualComponent deserialize(final Map<String, Object> map) {
if (map.containsKey("key") && (map.size() == 2) && map.containsKey("value")) {
// Arbitrary text component
return ArbitraryTextTypeComponent.deserialize(map);
} else if ((map.size() >= 2) && map.containsKey("key") && !map.containsKey("value") /* It contains keys that START WITH value */) {
// Complex JSON object
return ComplexTextTypeComponent.deserialize(map);
}
return null;
}
static boolean isTextKey(final String key) {
return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector");
}
static boolean isTranslatableText(final TextualComponent component) {
return (component instanceof ComplexTextTypeComponent) && ((ComplexTextTypeComponent) component).getKey().equals("translate");
}
/** /**
* Internal class used to represent all types of text components. * Internal class used to represent all types of text components.
@ -79,33 +173,37 @@ public abstract class TextualComponent implements Cloneable {
*/ */
private static final class ArbitraryTextTypeComponent extends TextualComponent implements ConfigurationSerializable { private static final class ArbitraryTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
public ArbitraryTextTypeComponent(final String key, final String value) { private String key;
private String value;
public ArbitraryTextTypeComponent(String key, String value) {
setKey(key); setKey(key);
setValue(value); setValue(value);
} }
@Override public static ArbitraryTextTypeComponent deserialize(Map<String, Object> map) {
public String getKey() { return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString());
return _key;
} }
public void setKey(final String key) { @Override
Preconditions.checkArgument((key != null) && !key.isEmpty(), "The key must be specified."); public String getKey() {
_key = key; return key;
}
public void setKey(String key) {
Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
this.key = key;
} }
public String getValue() { public String getValue() {
return _value; return value;
} }
public void setValue(final String value) { public void setValue(String value) {
Preconditions.checkArgument(value != null, "The value must be specified."); Preconditions.checkArgument(value != null, "The value must be specified.");
_value = value; this.value = value;
} }
private String _key;
private String _value;
@Override @Override
public TextualComponent clone() throws CloneNotSupportedException { public TextualComponent clone() throws CloneNotSupportedException {
// Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone // Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone
@ -113,7 +211,7 @@ public abstract class TextualComponent implements Cloneable {
} }
@Override @Override
public void writeJson(final JsonWriter writer) throws IOException { public void writeJson(JsonWriter writer) throws IOException {
writer.name(getKey()).value(getValue()); writer.name(getKey()).value(getValue());
} }
@ -128,10 +226,6 @@ public abstract class TextualComponent implements Cloneable {
}; };
} }
public static ArbitraryTextTypeComponent deserialize(final Map<String, Object> map) {
return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString());
}
@Override @Override
public String getReadableString() { public String getReadableString() {
return getValue(); return getValue();
@ -139,49 +233,64 @@ public abstract class TextualComponent implements Cloneable {
} }
/** /**
* Internal class used to represent a text component with a nested JSON value. * Internal class used to represent a text component with a nested JSON
* Exception validating done is on keys and values. * value.
*
* <p>Exception validating done is on keys and values.
*/ */
private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable { private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
public ComplexTextTypeComponent(final String key, final Map<String, String> values) { private String key;
private Map<String, String> value;
public ComplexTextTypeComponent(String key, Map<String, String> values) {
setKey(key); setKey(key);
setValue(values); setValue(values);
} }
@Override public static ComplexTextTypeComponent deserialize(Map<String, Object> map) {
public String getKey() { String key = null;
return _key; Map<String, String> value = new HashMap<>();
for (Map.Entry<String, Object> valEntry : map.entrySet()) {
if (valEntry.getKey().equals("key")) {
key = (String) valEntry.getValue();
} else if (valEntry.getKey().startsWith("value.")) {
value.put(valEntry.getKey().substring(6) /* Strips out the value prefix */, valEntry.getValue().toString());
}
}
return new ComplexTextTypeComponent(key, value);
} }
public void setKey(final String key) { @Override
Preconditions.checkArgument((key != null) && !key.isEmpty(), "The key must be specified."); public String getKey() {
_key = key; return key;
}
public void setKey(String key) {
Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
this.key = key;
} }
public Map<String, String> getValue() { public Map<String, String> getValue() {
return _value; return value;
} }
public void setValue(final Map<String, String> value) { public void setValue(Map<String, String> value) {
Preconditions.checkArgument(value != null, "The value must be specified."); Preconditions.checkArgument(value != null, "The value must be specified.");
_value = value; this.value = value;
} }
private String _key;
private Map<String, String> _value;
@Override @Override
public TextualComponent clone() throws CloneNotSupportedException { public TextualComponent clone() {
// Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone // Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone
return new ComplexTextTypeComponent(getKey(), getValue()); return new ComplexTextTypeComponent(getKey(), getValue());
} }
@Override @Override
public void writeJson(final JsonWriter writer) throws IOException { public void writeJson(JsonWriter writer) throws IOException {
writer.name(getKey()); writer.name(getKey());
writer.beginObject(); writer.beginObject();
for (final Map.Entry<String, String> jsonPair : _value.entrySet()) { for (Map.Entry<String, String> jsonPair : value.entrySet()) {
writer.name(jsonPair.getKey()).value(jsonPair.getValue()); writer.name(jsonPair.getKey()).value(jsonPair.getValue());
} }
writer.endObject(); writer.endObject();
@ -193,101 +302,16 @@ public abstract class TextualComponent implements Cloneable {
return new java.util.HashMap<String, Object>() { return new java.util.HashMap<String, Object>() {
{ {
put("key", getKey()); put("key", getKey());
for (final Map.Entry<String, String> valEntry : getValue().entrySet()) { for (Map.Entry<String, String> valEntry : getValue().entrySet()) {
put("value." + valEntry.getKey(), valEntry.getValue()); put("value." + valEntry.getKey(), valEntry.getValue());
} }
} }
}; };
} }
public static ComplexTextTypeComponent deserialize(final Map<String, Object> map) {
String key = null;
final Map<String, String> value = new HashMap<String, String>();
for (final Map.Entry<String, Object> valEntry : map.entrySet()) {
if (valEntry.getKey().equals("key")) {
key = (String) valEntry.getValue();
} else if (valEntry.getKey().startsWith("value.")) {
value.put(valEntry.getKey().substring(6) /* Strips out the value prefix */, valEntry.getValue().toString());
}
}
return new ComplexTextTypeComponent(key, value);
}
@Override @Override
public String getReadableString() { public String getReadableString() {
return getKey(); return getKey();
} }
} }
/**
* Create a textual component representing a string literal.
* This is the default type of textual component when a single string literal is given to a method.
* @param textValue The text which will be represented.
* @return The text component representing the specified literal text.
*/
public static TextualComponent rawText(final String textValue) {
return new ArbitraryTextTypeComponent("text", textValue);
}
/**
* Create a textual component representing a localized string.
* The client will see this text component as their localized version of the specified string <em>key</em>, which can be overridden by a resource pack.
* <p>
* If the specified translation key is not present on the client resource pack, the translation key will be displayed as a string literal to the client.
* </p>
* @param translateKey The string key which maps to localized text.
* @return The text component representing the specified localized text.
*/
public static TextualComponent localizedText(final String translateKey) {
return new ArbitraryTextTypeComponent("translate", translateKey);
}
private static void throwUnsupportedSnapshot() {
throw new UnsupportedOperationException("This feature is only supported in snapshot releases.");
}
/**
* Create a textual component representing a scoreboard value.
* The client will see their own score for the specified objective as the text represented by this component.
* <p>
* <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b>
* </p>
* @param scoreboardObjective The name of the objective for which to display the score.
* @return The text component representing the specified scoreboard score (for the viewing player), or {@code null} if an error occurs during JSON serialization.
*/
public static TextualComponent objectiveScore(final String scoreboardObjective) {
return objectiveScore("*", scoreboardObjective);
}
/**
* Create a textual component representing a scoreboard value.
* The client will see the score of the specified player for the specified objective as the text represented by this component.
* <p>
* <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b>
* </p>
* @param playerName The name of the player whos score will be shown. If this string represents the single-character sequence "*", the viewing player's score will be displayed.
* Standard minecraft selectors (@a, @p, etc) are <em>not</em> supported.
* @param scoreboardObjective The name of the objective for which to display the score.
* @return The text component representing the specified scoreboard score for the specified player, or {@code null} if an error occurs during JSON serialization.
*/
public static TextualComponent objectiveScore(final String playerName, final String scoreboardObjective) {
throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE OVERLOADS documentation accordingly
return new ComplexTextTypeComponent("score", ImmutableMap.<String, String> builder().put("name", playerName).put("objective", scoreboardObjective).build());
}
/**
* Create a textual component representing a player name, retrievable by using a standard minecraft selector.
* The client will see the players or entities captured by the specified selector as the text represented by this component.
* <p>
* <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b>
* </p>
* @param selector The minecraft player or entity selector which will capture the entities whose string representations will be displayed in the place of this text component.
* @return The text component representing the name of the entities captured by the selector.
*/
public static TextualComponent selector(final String selector) {
throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE OVERLOADS documentation accordingly
return new ArbitraryTextTypeComponent("selector", selector);
}
} }

View File

@ -1,31 +1,11 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// PlotSquared - A plot manager and world generator for the Bukkit API /
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
// /
// This program is free software; you can redistribute it and/or modify /
// it under the terms of the GNU General Public License as published by /
// the Free Software Foundation; either version 3 of the License, or /
// (at your option) any later version. /
// /
// This program is distributed in the hope that it will be useful, /
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
// GNU General Public License for more details. /
// /
// You should have received a copy of the GNU General Public License /
// along with this program; if not, write to the Free Software Foundation, /
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
// /
// You can contact us via: support@intellectualsites.com /
////////////////////////////////////////////////////////////////////////////////////////////////////
package com.plotsquared.bukkit.commands; package com.plotsquared.bukkit.commands;
import com.google.common.collect.Sets;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.commands.CommandCategory; import com.intellectualcrafters.plot.commands.CommandCategory;
import com.intellectualcrafters.plot.commands.RequiredType; import com.intellectualcrafters.plot.commands.RequiredType;
import com.intellectualcrafters.plot.commands.SubCommand; import com.intellectualcrafters.plot.commands.SubCommand;
import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.database.AbstractDB;
import com.intellectualcrafters.plot.database.DBFunc; import com.intellectualcrafters.plot.database.DBFunc;
import com.intellectualcrafters.plot.object.OfflinePlotPlayer; import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.Plot;
@ -37,14 +17,13 @@ import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.UUIDHandler; import com.intellectualcrafters.plot.util.UUIDHandler;
import com.intellectualcrafters.plot.util.WorldUtil; import com.intellectualcrafters.plot.util.WorldUtil;
import com.intellectualcrafters.plot.uuid.UUIDWrapper; import com.intellectualcrafters.plot.uuid.UUIDWrapper;
import com.plotsquared.bukkit.uuid.DatFileFilter;
import com.plotsquared.bukkit.uuid.DefaultUUIDWrapper; import com.plotsquared.bukkit.uuid.DefaultUUIDWrapper;
import com.plotsquared.bukkit.uuid.LowerOfflineUUIDWrapper; import com.plotsquared.bukkit.uuid.LowerOfflineUUIDWrapper;
import com.plotsquared.bukkit.uuid.OfflineUUIDWrapper; import com.plotsquared.bukkit.uuid.OfflineUUIDWrapper;
import com.plotsquared.general.commands.Argument; import com.plotsquared.general.commands.Argument;
import com.plotsquared.general.commands.CommandDeclaration; import com.plotsquared.general.commands.CommandDeclaration;
import java.io.File; import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
@ -65,11 +44,11 @@ category = CommandCategory.DEBUG)
public class DebugUUID extends SubCommand { public class DebugUUID extends SubCommand {
public DebugUUID() { public DebugUUID() {
requiredArguments = new Argument[] { Argument.String }; super(Argument.String);
} }
@Override @Override
public boolean onCommand(final PlotPlayer player, final String[] args) { public boolean onCommand(final PlotPlayer player, String[] args) {
final UUIDWrapper currentUUIDWrapper = UUIDHandler.getUUIDWrapper(); final UUIDWrapper currentUUIDWrapper = UUIDHandler.getUUIDWrapper();
final UUIDWrapper newWrapper; final UUIDWrapper newWrapper;
@ -85,9 +64,9 @@ public class DebugUUID extends SubCommand {
break; break;
default: default:
try { try {
final Class<?> clazz = Class.forName(args[0]); Class<?> clazz = Class.forName(args[0]);
newWrapper = (UUIDWrapper) clazz.newInstance(); newWrapper = (UUIDWrapper) clazz.newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { } catch (ClassNotFoundException | IllegalAccessException | InstantiationException ignored) {
MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot uuidconvert <lower|offline|online>"); MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot uuidconvert <lower|offline|online>");
return false; return false;
} }
@ -112,7 +91,7 @@ public class DebugUUID extends SubCommand {
MainUtil.sendMessage(player, "&6Beginning UUID mode conversion"); MainUtil.sendMessage(player, "&6Beginning UUID mode conversion");
MainUtil.sendMessage(player, "&7 - Disconnecting players"); MainUtil.sendMessage(player, "&7 - Disconnecting players");
for (Entry<String, PlotPlayer> entry : UUIDHandler.getPlayers().entrySet()) { for (Entry<String, PlotPlayer> entry : UUIDHandler.getPlayers().entrySet()) {
entry.getValue().kick("PlotSquared UUID conversion has been initiated. You may reconnect when finished."); entry.getValue().kick("UUID conversion has been initiated. You may reconnect when finished.");
} }
MainUtil.sendMessage(player, "&7 - Initializing map"); MainUtil.sendMessage(player, "&7 - Initializing map");
@ -122,38 +101,27 @@ public class DebugUUID extends SubCommand {
MainUtil.sendMessage(player, "&7 - Collecting playerdata"); MainUtil.sendMessage(player, "&7 - Collecting playerdata");
final HashSet<String> worlds = new HashSet<>(); HashSet<String> worlds = Sets.newHashSet(WorldUtil.IMP.getMainWorld(), "world");
worlds.add(WorldUtil.IMP.getMainWorld()); HashSet<UUID> uuids = new HashSet<>();
worlds.add("world"); HashSet<String> names = new HashSet<>();
final HashSet<UUID> uuids = new HashSet<>(); for (String worldName : worlds) {
final HashSet<String> names = new HashSet<>(); File playerDataFolder = new File(worldName + File.separator + "playerdata");
for (final String worldname : worlds) { String[] dat = playerDataFolder.list(new DatFileFilter());
final File playerdataFolder = new File(worldname + File.separator + "playerdata");
String[] dat = playerdataFolder.list(new FilenameFilter() {
@Override
public boolean accept(final File f, final String s) {
return s.endsWith(".dat");
}
});
if (dat != null)
for (final String current : dat) {
final String s = current.replaceAll(".dat$", "");
try {
final UUID uuid = UUID.fromString(s);
uuids.add(uuid);
} catch (final Exception e) {
MainUtil.sendMessage(player, C.PREFIX.s() + "Invalid playerdata: " + current);
}
}
final File playersFolder = new File(worldname + File.separator + "players");
dat = playersFolder.list(new FilenameFilter() {
@Override
public boolean accept(final File f, final String s) {
return s.endsWith(".dat");
}
});
if (dat != null) { if (dat != null) {
for (final String current : dat) { for (String current : dat) {
String s = current.replaceAll(".dat$", "");
try {
UUID uuid = UUID.fromString(s);
uuids.add(uuid);
} catch (Exception ignored) {
MainUtil.sendMessage(player, C.PREFIX + "Invalid playerdata: " + current);
}
}
}
File playersFolder = new File(worldName + File.separator + "players");
dat = playersFolder.list(new DatFileFilter());
if (dat != null) {
for (String current : dat) {
names.add(current.replaceAll(".dat$", "")); names.add(current.replaceAll(".dat$", ""));
} }
} }
@ -161,22 +129,22 @@ public class DebugUUID extends SubCommand {
MainUtil.sendMessage(player, "&7 - Populating map"); MainUtil.sendMessage(player, "&7 - Populating map");
UUID uuid2; UUID uuid2;
final UUIDWrapper wrapper = new DefaultUUIDWrapper(); UUIDWrapper wrapper = new DefaultUUIDWrapper();
for (UUID uuid : uuids) { for (UUID uuid : uuids) {
try { try {
final OfflinePlotPlayer op = wrapper.getOfflinePlayer(uuid); OfflinePlotPlayer op = wrapper.getOfflinePlayer(uuid);
uuid = currentUUIDWrapper.getUUID(op); uuid = currentUUIDWrapper.getUUID(op);
uuid2 = newWrapper.getUUID(op); uuid2 = newWrapper.getUUID(op);
if (!uuid.equals(uuid2) && !uCMap.containsKey(uuid) && !uCReverse.containsKey(uuid2)) { if (!uuid.equals(uuid2) && !uCMap.containsKey(uuid) && !uCReverse.containsKey(uuid2)) {
uCMap.put(uuid, uuid2); uCMap.put(uuid, uuid2);
uCReverse.put(uuid2, uuid); uCReverse.put(uuid2, uuid);
} }
} catch (final Throwable e) { } catch (Throwable ignored) {
MainUtil.sendMessage(player, C.PREFIX.s() + "&6Invalid playerdata: " + uuid.toString() + ".dat"); MainUtil.sendMessage(player, C.PREFIX + "&6Invalid playerdata: " + uuid.toString() + ".dat");
} }
} }
for (final String name : names) { for (String name : names) {
final UUID uuid = currentUUIDWrapper.getUUID(name); UUID uuid = currentUUIDWrapper.getUUID(name);
uuid2 = newWrapper.getUUID(name); uuid2 = newWrapper.getUUID(name);
if (!uuid.equals(uuid2)) { if (!uuid.equals(uuid2)) {
uCMap.put(uuid, uuid2); uCMap.put(uuid, uuid2);
@ -185,11 +153,11 @@ public class DebugUUID extends SubCommand {
} }
if (uCMap.isEmpty()) { if (uCMap.isEmpty()) {
MainUtil.sendMessage(player, "&c - Error! Attempting to repopulate"); MainUtil.sendMessage(player, "&c - Error! Attempting to repopulate");
for (final OfflinePlotPlayer op : currentUUIDWrapper.getOfflinePlayers()) { for (OfflinePlotPlayer op : currentUUIDWrapper.getOfflinePlayers()) {
if (op.getLastPlayed() != 0) { if (op.getLastPlayed() != 0) {
// String name = op.getName(); // String name = op.getPluginName();
// StringWrapper wrap = new StringWrapper(name); // StringWrapper wrap = new StringWrapper(name);
final UUID uuid = currentUUIDWrapper.getUUID(op); UUID uuid = currentUUIDWrapper.getUUID(op);
uuid2 = newWrapper.getUUID(op); uuid2 = newWrapper.getUUID(op);
if (!uuid.equals(uuid2)) { if (!uuid.equals(uuid2)) {
uCMap.put(uuid, uuid2); uCMap.put(uuid, uuid2);
@ -209,8 +177,8 @@ public class DebugUUID extends SubCommand {
TaskManager.runTaskAsync(new Runnable() { TaskManager.runTaskAsync(new Runnable() {
@Override @Override
public void run() { public void run() {
for (final Entry<UUID, UUID> entry : uCMap.entrySet()) { for (Entry<UUID, UUID> entry : uCMap.entrySet()) {
final String name = UUIDHandler.getName(entry.getKey()); String name = UUIDHandler.getName(entry.getKey());
if (name != null) { if (name != null) {
UUIDHandler.add(new StringWrapper(name), entry.getValue()); UUIDHandler.add(new StringWrapper(name), entry.getValue());
} }
@ -218,10 +186,10 @@ public class DebugUUID extends SubCommand {
MainUtil.sendMessage(player, "&7 - Scanning for applicable files (uuids.txt)"); MainUtil.sendMessage(player, "&7 - Scanning for applicable files (uuids.txt)");
final File file = new File(PS.get().IMP.getDirectory(), "uuids.txt"); File file = new File(PS.get().IMP.getDirectory(), "uuids.txt");
if (file.exists()) { if (file.exists()) {
try { try {
final List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8); List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
for (String line : lines) { for (String line : lines) {
try { try {
line = line.trim(); line = line.trim();
@ -229,24 +197,24 @@ public class DebugUUID extends SubCommand {
continue; continue;
} }
line = line.replaceAll("[\\|][0-9]+[\\|][0-9]+[\\|]", ""); line = line.replaceAll("[\\|][0-9]+[\\|][0-9]+[\\|]", "");
final String[] split = line.split("\\|"); String[] split = line.split("\\|");
final String name = split[0]; String name = split[0];
if (name.isEmpty() || name.length() > 16 || !StringMan.isAlphanumericUnd(name)) { if (name.isEmpty() || name.length() > 16 || !StringMan.isAlphanumericUnd(name)) {
continue; continue;
} }
final UUID old = currentUUIDWrapper.getUUID(name); UUID old = currentUUIDWrapper.getUUID(name);
if (old == null) { if (old == null) {
continue; continue;
} }
final UUID now = newWrapper.getUUID(name); UUID now = newWrapper.getUUID(name);
UUIDHandler.add(new StringWrapper(name), now); UUIDHandler.add(new StringWrapper(name), now);
uCMap.put(old, now); uCMap.put(old, now);
uCReverse.put(now, old); uCReverse.put(now, old);
} catch (final Exception e2) { } catch (Exception e2) {
e2.printStackTrace(); e2.printStackTrace();
} }
} }
} catch (final IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -256,8 +224,8 @@ public class DebugUUID extends SubCommand {
MainUtil.sendMessage(player, "&7 - Updating plot objects"); MainUtil.sendMessage(player, "&7 - Updating plot objects");
for (final Plot plot : PS.get().getPlots()) { for (Plot plot : PS.get().getPlots()) {
final UUID value = uCMap.get(plot.owner); UUID value = uCMap.get(plot.owner);
if (value != null) { if (value != null) {
plot.owner = value; plot.owner = value;
} }
@ -267,22 +235,21 @@ public class DebugUUID extends SubCommand {
} }
MainUtil.sendMessage(player, "&7 - Deleting database"); MainUtil.sendMessage(player, "&7 - Deleting database");
final AbstractDB database = DBFunc.dbManager; boolean result = DBFunc.deleteTables();
final boolean result = database.deleteTables();
MainUtil.sendMessage(player, "&7 - Creating tables"); MainUtil.sendMessage(player, "&7 - Creating tables");
try { try {
database.createTables(); DBFunc.createTables();
if (!result) { if (!result) {
MainUtil.sendMessage(player, "&cConversion failed! Attempting recovery"); MainUtil.sendMessage(player, "&cConversion failed! Attempting recovery");
for (final Plot plot : PS.get().getPlots()) { for (Plot plot : PS.get().getPlots()) {
final UUID value = uCReverse.get(plot.owner); UUID value = uCReverse.get(plot.owner);
if (value != null) { if (value != null) {
plot.owner = value; plot.owner = value;
} }
} }
database.createPlotsAndData(new ArrayList<>(PS.get().getPlots()), new Runnable() { DBFunc.createPlotsAndData(new ArrayList<>(PS.get().getPlots()), new Runnable() {
@Override @Override
public void run() { public void run() {
MainUtil.sendMessage(player, "&6Recovery was successful!"); MainUtil.sendMessage(player, "&6Recovery was successful!");
@ -290,22 +257,22 @@ public class DebugUUID extends SubCommand {
}); });
return; return;
} }
} catch (final Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return; return;
} }
if (newWrapper instanceof OfflineUUIDWrapper) { if (newWrapper instanceof OfflineUUIDWrapper) {
PS.get().config.set("UUID.force-lowercase", false); PS.get().worlds.set("UUID.force-lowercase", false);
PS.get().config.set("UUID.offline", true); PS.get().worlds.set("UUID.offline", true);
} else if (newWrapper instanceof DefaultUUIDWrapper) { } else if (newWrapper instanceof DefaultUUIDWrapper) {
PS.get().config.set("UUID.force-lowercase", false); PS.get().worlds.set("UUID.force-lowercase", false);
PS.get().config.set("UUID.offline", false); PS.get().worlds.set("UUID.offline", false);
} }
try { try {
PS.get().config.save(PS.get().configFile); PS.get().worlds.save(PS.get().worldsFile);
} catch (IOException e) { } catch (IOException ignored) {
MainUtil.sendMessage(player, "Could not save configuration. It will need to be manuall set!"); MainUtil.sendMessage(player, "Could not save configuration. It will need to be manual set!");
} }
MainUtil.sendMessage(player, "&7 - Populating tables"); MainUtil.sendMessage(player, "&7 - Populating tables");
@ -313,8 +280,8 @@ public class DebugUUID extends SubCommand {
TaskManager.runTaskAsync(new Runnable() { TaskManager.runTaskAsync(new Runnable() {
@Override @Override
public void run() { public void run() {
final ArrayList<Plot> plots = new ArrayList<>(PS.get().getPlots()); ArrayList<Plot> plots = new ArrayList<>(PS.get().getPlots());
database.createPlotsAndData(plots, new Runnable() { DBFunc.createPlotsAndData(plots, new Runnable() {
@Override @Override
public void run() { public void run() {
MainUtil.sendMessage(player, "&aConversion complete!"); MainUtil.sendMessage(player, "&aConversion complete!");

View File

@ -0,0 +1,82 @@
package com.plotsquared.bukkit.database.plotme;
import com.intellectualcrafters.configuration.file.FileConfiguration;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
public abstract class APlotMeConnector {
public abstract Connection getPlotMeConnection(String plugin, FileConfiguration plotConfig, String dataFolder);
public abstract HashMap<String, HashMap<PlotId, Plot>> getPlotMePlots(Connection connection) throws SQLException;
public abstract boolean accepts(String version);
public boolean isValidConnection(Connection connection) {
return connection != null;
}
public void copyConfig(FileConfiguration plotConfig, String world, String actualWorldName) {
int pathWidth = plotConfig.getInt("worlds." + world + ".PathWidth"); //
PS.get().worlds.set("worlds." + actualWorldName + ".road.width", pathWidth);
int plotSize = plotConfig.getInt("worlds." + world + ".PlotSize"); //
PS.get().worlds.set("worlds." + actualWorldName + ".plot.size", plotSize);
String wallBlock = plotConfig.getString("worlds." + world + ".WallBlockId"); //
PS.get().worlds.set("worlds." + actualWorldName + ".wall.block", wallBlock);
String floor = plotConfig.getString("worlds." + world + ".PlotFloorBlockId"); //
PS.get().worlds.set("worlds." + actualWorldName + ".plot.floor", Collections.singletonList(floor));
String filling = plotConfig.getString("worlds." + world + ".PlotFillingBlockId"); //
PS.get().worlds.set("worlds." + actualWorldName + ".plot.filling", Collections.singletonList(filling));
String road = plotConfig.getString("worlds." + world + ".RoadMainBlockId");
PS.get().worlds.set("worlds." + actualWorldName + ".road.block", road);
int height = plotConfig.getInt("worlds." + world + ".RoadHeight"); //
PS.get().worlds.set("worlds." + actualWorldName + ".road.height", height);
PS.get().worlds.set("worlds." + actualWorldName + ".plot.height", height);
PS.get().worlds.set("worlds." + actualWorldName + ".wall.height", height);
}
public Location getPlotTopLocAbs(int path, int plot, PlotId plotId) {
int px = plotId.x;
int pz = plotId.y;
int x = px * (path + plot) - (int) Math.floor(path / 2) - 1;
int z = pz * (path + plot) - (int) Math.floor(path / 2) - 1;
return new Location(null, x, 256, z);
}
public Location getPlotBottomLocAbs(int path, int plot, PlotId plotId) {
int px = plotId.x;
int pz = plotId.y;
int x = px * (path + plot) - plot - (int) Math.floor(path / 2) - 1;
int z = pz * (path + plot) - plot - (int) Math.floor(path / 2) - 1;
return new Location(null, x, 1, z);
}
public void setMerged(HashMap<String, HashMap<PlotId, boolean[]>> merges, String world, PlotId id, int direction) {
HashMap<PlotId, boolean[]> plots = merges.get(world);
PlotId id2 = new PlotId(id.x, id.y);
boolean[] merge1;
if (plots.containsKey(id)) {
merge1 = plots.get(id);
} else {
merge1 = new boolean[] { false, false, false, false };
}
boolean[] merge2;
if (plots.containsKey(id2)) {
merge2 = plots.get(id2);
} else {
merge2 = new boolean[] { false, false, false, false };
}
merge1[direction] = true;
merge2[(direction + 2) % 4] = true;
plots.put(id, merge1);
plots.put(id2, merge1);
}
}

View File

@ -0,0 +1,239 @@
package com.plotsquared.bukkit.database.plotme;
import com.google.common.base.Charsets;
import com.intellectualcrafters.configuration.file.FileConfiguration;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.database.DBFunc;
import com.intellectualcrafters.plot.database.SQLite;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.StringWrapper;
import com.intellectualcrafters.plot.util.UUIDHandler;
import java.io.File;
import java.nio.ByteBuffer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.UUID;
public class ClassicPlotMeConnector extends APlotMeConnector {
private String plugin = "PlotMe";
private String prefix;
@Override
public Connection getPlotMeConnection(String plugin, FileConfiguration plotConfig, String dataFolder) {
this.plugin = plugin.toLowerCase();
this.prefix = plotConfig.getString("mySQLprefix", this.plugin.toLowerCase());
try {
if (plotConfig.getBoolean("usemySQL")) {
String user = plotConfig.getString("mySQLuname");
String password = plotConfig.getString("mySQLpass");
String con = plotConfig.getString("mySQLconn");
return DriverManager.getConnection(con, user, password);
} else {
return new SQLite(new File(dataFolder + File.separator + "plots.db")).openConnection();
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@Override
public HashMap<String, HashMap<PlotId, Plot>> getPlotMePlots(Connection connection) throws SQLException {
HashMap<String, Integer> plotWidth = new HashMap<>();
HashMap<String, Integer> roadWidth = new HashMap<>();
HashMap<String, HashMap<PlotId, Plot>> plots = new HashMap<>();
HashMap<String, HashMap<PlotId, boolean[]>> merges = new HashMap<>();
PreparedStatement statement = connection.prepareStatement("SELECT * FROM `" + this.prefix + "Plots`");
ResultSet resultSet = statement.executeQuery();
String column = null;
boolean checkUUID = DBFunc.hasColumn(resultSet, "ownerid");
boolean checkUUID2 = DBFunc.hasColumn(resultSet, "ownerId");
if (checkUUID) {
column = "ownerid";
} else if (checkUUID2) {
column = "ownerId";
}
boolean merge = !"plotme".equalsIgnoreCase(this.plugin) && Settings.Enabled_Components.PLOTME_CONVERTER;
int missing = 0;
while (resultSet.next()) {
PlotId id = new PlotId(resultSet.getInt("idX"), resultSet.getInt("idZ"));
String name = resultSet.getString("owner");
String world = LikePlotMeConverter.getWorld(resultSet.getString("world"));
if (!plots.containsKey(world)) {
plots.put(world, new HashMap<PlotId, Plot>());
if (merge) {
int plot = PS.get().worlds.getInt("worlds." + world + ".plot.size");
int path = PS.get().worlds.getInt("worlds." + world + ".road.width");
plotWidth.put(world, plot);
roadWidth.put(world, path);
merges.put(world, new HashMap<PlotId, boolean[]>());
}
}
if (merge) {
int tx = resultSet.getInt("topX");
int tz = resultSet.getInt("topZ");
int bx = resultSet.getInt("bottomX") - 1;
int bz = resultSet.getInt("bottomZ") - 1;
int path = roadWidth.get(world);
int plot = plotWidth.get(world);
Location top = getPlotTopLocAbs(path, plot, id);
Location bot = getPlotBottomLocAbs(path, plot, id);
if (tx > top.getX()) {
setMerged(merges, world, id, 1);
}
if (tz > top.getZ()) {
setMerged(merges, world, id, 2);
}
if (bx < bot.getX()) {
setMerged(merges, world, id, 3);
}
if (bz > bot.getZ()) {
setMerged(merges, world, id, 0);
}
}
UUID owner = UUIDHandler.getUUID(name, null);
if (owner == null) {
if ("*".equals(name)) {
owner = DBFunc.everyone;
} else {
if (checkUUID || checkUUID2) {
byte[] bytes = resultSet.getBytes(column);
if (bytes != null) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
long high = bb.getLong();
long low = bb.getLong();
owner = new UUID(high, low);
UUIDHandler.add(new StringWrapper(name), owner);
}
}
if (name.isEmpty()) {
PS.log("&cCould not identify owner for plot: " + id + " -> '" + name + "'");
missing++;
continue;
}
owner = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name.toLowerCase()).getBytes(Charsets.UTF_8));
}
} else {
UUIDHandler.add(new StringWrapper(name), owner);
}
Plot plot = new Plot(PlotArea.createGeneric(world), id, owner);
plots.get(world).put(id, plot);
}
if (missing > 0) {
PS.log("&cSome names could not be identified:");
PS.log("&7 - Empty quotes mean PlotMe just stored an unowned plot in the database");
PS.log("&7 - Names you have never seen before could be from people mistyping commands");
PS.log("&7 - Converting from a non-uuid version of PlotMe can't identify owners if the playerdata files are deleted (these plots will "
+ "remain unknown until the player connects)");
}
for (Entry<String, HashMap<PlotId, boolean[]>> entry : merges.entrySet()) {
String world = entry.getKey();
for (Entry<PlotId, boolean[]> entry2 : entry.getValue().entrySet()) {
HashMap<PlotId, Plot> newPlots = plots.get(world);
Plot plot = newPlots.get(entry2.getKey());
if (plot != null) {
plot.setMerged(entry2.getValue());
}
}
}
resultSet.close();
statement.close();
try {
PS.log(" - " + this.prefix + "Denied");
statement = connection.prepareStatement("SELECT * FROM `" + this.prefix + "Denied`");
resultSet = statement.executeQuery();
while (resultSet.next()) {
PlotId id = new PlotId(resultSet.getInt("idX"), resultSet.getInt("idZ"));
String name = resultSet.getString("player");
String world = LikePlotMeConverter.getWorld(resultSet.getString("world"));
UUID denied = UUIDHandler.getUUID(name, null);
if (denied == null) {
if ("*".equals(name)) {
denied = DBFunc.everyone;
} else if (DBFunc.hasColumn(resultSet, "playerid")) {
byte[] bytes = resultSet.getBytes("playerid");
if (bytes != null) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
long mostSigBits = bb.getLong();
long leastSigBits = bb.getLong();
denied = new UUID(mostSigBits, leastSigBits);
UUIDHandler.add(new StringWrapper(name), denied);
}
}
if (denied == null) {
PS.log("&6Could not identify denied for plot: " + id);
continue;
}
}
HashMap<PlotId, Plot> worldMap = plots.get(world);
if (worldMap != null) {
Plot plot = worldMap.get(id);
if (plot != null) {
plot.getDenied().add(denied);
}
}
}
statement = connection.prepareStatement("SELECT * FROM `" + this.plugin + "Allowed`");
resultSet = statement.executeQuery();
while (resultSet.next()) {
PlotId id = new PlotId(resultSet.getInt("idX"), resultSet.getInt("idZ"));
String name = resultSet.getString("player");
String world = LikePlotMeConverter.getWorld(resultSet.getString("world"));
UUID helper = UUIDHandler.getUUID(name, null);
if (helper == null) {
if ("*".equals(name)) {
helper = DBFunc.everyone;
} else if (DBFunc.hasColumn(resultSet, "playerid")) {
byte[] bytes = resultSet.getBytes("playerid");
if (bytes != null) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
long mostSigBits = bb.getLong();
long leastSigBits = bb.getLong();
helper = new UUID(mostSigBits, leastSigBits);
UUIDHandler.add(new StringWrapper(name), helper);
}
}
if (helper == null) {
PS.log("&6Could not identify helper for plot: " + id);
continue;
}
}
HashMap<PlotId, Plot> worldMap = plots.get(world);
if (worldMap != null) {
Plot plot = worldMap.get(id);
if (plot != null) {
plot.getTrusted().add(helper);
}
}
}
resultSet.close();
statement.close();
} catch (SQLException ignored) {}
return plots;
}
@Override
public boolean accepts(String version) {
return version == null || PS.get().canUpdate(version, "0.17.0") || PS.get().canUpdate("0.999.999", version);
}
}

View File

@ -0,0 +1,362 @@
package com.plotsquared.bukkit.database.plotme;
import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.configuration.MemorySection;
import com.intellectualcrafters.configuration.file.FileConfiguration;
import com.intellectualcrafters.configuration.file.YamlConfiguration;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.database.DBFunc;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.util.TaskManager;
import com.plotsquared.bukkit.generator.BukkitPlotGenerator;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.command.CommandException;
public class LikePlotMeConverter {
private final String plugin;
public LikePlotMeConverter(String plugin) {
this.plugin = plugin;
}
public static String getWorld(String world) {
for (World newWorld : Bukkit.getWorlds()) {
if (newWorld.getName().equalsIgnoreCase(world)) {
return newWorld.getName();
}
}
return world;
}
private void sendMessage(String message) {
PS.debug("&3PlotMe&8->&3" + PS.imp().getPluginName() + "&8: &7" + message);
}
public String getPlotMePath() {
return new File(".").getAbsolutePath() + File.separator + "plugins" + File.separator + plugin + File.separator;
}
public FileConfiguration getPlotMeConfig(String dataFolder) {
File plotMeFile = new File(dataFolder + "config.yml");
if (!plotMeFile.exists()) {
return null;
}
return YamlConfiguration.loadConfiguration(plotMeFile);
}
public Set<String> getPlotMeWorlds(FileConfiguration plotConfig) {
return plotConfig.getConfigurationSection("worlds").getKeys(false);
}
public void mergeWorldYml(FileConfiguration plotConfig) {
try {
File genConfig =
new File("plugins" + File.separator + plugin + File.separator + "PlotMe-DefaultGenerator" + File.separator + "config.yml");
if (genConfig.exists()) {
YamlConfiguration yml = YamlConfiguration.loadConfiguration(genConfig);
for (String key : yml.getKeys(true)) {
if (!plotConfig.contains(key)) {
Object value = yml.get(key);
if (!(value instanceof MemorySection)) {
plotConfig.set(key, value);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void updateWorldYml(String location) {
try {
Path path = Paths.get(location);
File file = new File(location);
if (!file.exists()) {
return;
}
String content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
String pluginName = PS.imp().getPluginName();
content = content.replace("PlotMe-DefaultGenerator", pluginName);
content = content.replace("PlotMe", pluginName);
content = content.replace("AthionPlots", pluginName);
content = content.replace("PlotZWorld", pluginName);
Files.write(path, content.getBytes(StandardCharsets.UTF_8));
} catch (IOException ignored) {}
}
private void copyConfig(ConfigurationSection plotmeDgYml, String world) throws IOException {
String actualWorldName = getWorld(world);
String plotMeWorldName = world.toLowerCase();
Integer pathWidth = plotmeDgYml.getInt("worlds." + plotMeWorldName + ".PathWidth"); //
PS.get().worlds.set("worlds." + world + ".road.width", pathWidth);
int height = plotmeDgYml.getInt("worlds." + plotMeWorldName + ".RoadHeight", plotmeDgYml.getInt("worlds." + plotMeWorldName + ".GroundHeight", 64)); //
PS.get().worlds.set("worlds." + world + ".road.height", height);
PS.get().worlds.set("worlds." + world + ".wall.height", height);
PS.get().worlds.set("worlds." + world + ".plot.height", height);
int plotSize = plotmeDgYml.getInt("worlds." + plotMeWorldName + ".PlotSize", 32); //
PS.get().worlds.set("worlds." + world + ".plot.size", plotSize);
String wallblock = plotmeDgYml.getString("worlds." + plotMeWorldName + ".UnclaimedBorder", plotmeDgYml.getString("worlds." + plotMeWorldName + ".WallBlock", "44")); //
PS.get().worlds.set("worlds." + world + ".wall.block", wallblock);
String claimed = plotmeDgYml.getString("worlds." + plotMeWorldName + ".ProtectedWallBlock", "44:1"); //
PS.get().worlds.set("worlds." + world + ".wall.block_claimed", claimed);
String floor = plotmeDgYml.getString("worlds." + plotMeWorldName + ".PlotFloorBlock", "2"); //
PS.get().worlds.set("worlds." + world + ".plot.floor", Collections.singletonList(floor));
String filling = plotmeDgYml.getString("worlds." + plotMeWorldName + ".FillBlock", "3"); //
PS.get().worlds.set("worlds." + world + ".plot.filling", Collections.singletonList(filling));
String road = plotmeDgYml.getString("worlds." + plotMeWorldName + ".RoadMainBlock", "5");
PS.get().worlds.set("worlds." + world + ".road.block", road);
PS.get().worlds.set("worlds." + actualWorldName + ".road.height", height);
PS.get().worlds.set("worlds." + actualWorldName + ".plot.height", height);
PS.get().worlds.set("worlds." + actualWorldName + ".wall.height", height);
PS.get().worlds.save(PS.get().worldsFile);
}
public boolean run(APlotMeConnector connector) {
try {
String dataFolder = getPlotMePath();
FileConfiguration plotConfig = getPlotMeConfig(dataFolder);
if (plotConfig == null) {
return false;
}
String version = plotConfig.getString("Version");
if (version == null) {
version = plotConfig.getString("version");
}
if (!connector.accepts(version)) {
return false;
}
PS.debug("&3Using connector: " + connector.getClass().getCanonicalName());
Connection connection = connector.getPlotMeConnection(plugin,plotConfig, dataFolder);
if (!connector.isValidConnection(connection)) {
sendMessage("Cannot connect to PlotMe DB. Conversion process will not continue");
return false;
}
sendMessage("PlotMe conversion has started. To disable this, please set 'enabled-components -> plotme-converter' to false in the 'settings.yml'");
mergeWorldYml(plotConfig);
sendMessage("Connecting to PlotMe DB");
ArrayList<Plot> createdPlots = new ArrayList<>();
sendMessage("Collecting plot data");
String dbPrefix = "PlotMe".toLowerCase();
sendMessage(" - " + dbPrefix + "Plots");
final Set<String> worlds = getPlotMeWorlds(plotConfig);
if (Settings.Enabled_Components.PLOTME_CONVERTER) {
sendMessage("Updating bukkit.yml");
updateWorldYml("bukkit.yml");
updateWorldYml("plugins/Multiverse-Core/worlds.yml");
for (String world : plotConfig.getConfigurationSection("worlds").getKeys(false)) {
sendMessage("Copying config for: " + world);
try {
String actualWorldName = getWorld(world);
connector.copyConfig(plotConfig, world, actualWorldName);
PS.get().worlds.save(PS.get().worldsFile);
} catch (IOException e) {
e.printStackTrace();
sendMessage("&c-- &lFailed to save configuration for world '" + world
+ "'\nThis will need to be done using the setup command, or manually");
}
}
}
HashMap<String, HashMap<PlotId, Plot>> plots = connector.getPlotMePlots(connection);
int plotCount = 0;
for (Entry<String, HashMap<PlotId, Plot>> entry : plots.entrySet()) {
plotCount += entry.getValue().size();
}
if (!Settings.Enabled_Components.PLOTME_CONVERTER) {
return false;
}
sendMessage(" - " + dbPrefix + "Allowed");
sendMessage("Collected " + plotCount + " plots from PlotMe");
File plotmeDgFile = new File(dataFolder + File.separator + "PlotMe-DefaultGenerator" + File.separator + "config.yml");
if (plotmeDgFile.exists()) {
YamlConfiguration plotmeDgYml = YamlConfiguration.loadConfiguration(plotmeDgFile);
try {
HashSet<String> allWorlds = new HashSet<>(plots.keySet());
allWorlds.addAll(worlds);
for (String world : allWorlds) {
copyConfig(plotmeDgYml, world);
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
for (Entry<String, HashMap<PlotId, Plot>> entry : plots.entrySet()) {
String world = entry.getKey();
PlotArea area = PS.get().getPlotArea(world, null);
int duplicate = 0;
if (area != null) {
for (Entry<PlotId, Plot> entry2 : entry.getValue().entrySet()) {
if (area.getOwnedPlotAbs(entry2.getKey()) != null) {
duplicate++;
} else {
createdPlots.add(entry2.getValue());
}
}
if (duplicate > 0) {
PS.debug("&c[WARNING] Found " + duplicate + " duplicate plots already in DB for world: '" + world
+ "'. Have you run the converter already?");
}
} else {
if (PS.get().plots_tmp != null) {
HashMap<PlotId, Plot> map = PS.get().plots_tmp.get(world);
if (map != null) {
for (Entry<PlotId, Plot> entry2 : entry.getValue().entrySet()) {
if (map.containsKey(entry2.getKey())) {
duplicate++;
} else {
createdPlots.add(entry2.getValue());
}
}
if (duplicate > 0) {
PS.debug("&c[WARNING] Found " + duplicate + " duplicate plots already in DB for world: '" + world
+ "'. Have you run the converter already?");
}
continue;
}
}
createdPlots.addAll(entry.getValue().values());
}
}
sendMessage("Creating plot DB");
Thread.sleep(1000);
final AtomicBoolean done = new AtomicBoolean(false);
DBFunc.createPlotsAndData(createdPlots, new Runnable() {
@Override
public void run() {
if (done.get()) {
done();
sendMessage("&aDatabase conversion is now complete!");
PS.debug("&c - Stop the server");
PS.debug("&c - Disable 'plotme-converter' and 'plotme-convert.cache-uuids' in the settings.yml");
PS.debug("&c - Correct any generator settings that haven't copied to 'settings.yml' properly");
PS.debug("&c - Start the server");
PS.get().setPlots(DBFunc.getPlots());
} else {
sendMessage("&cPlease wait until database conversion is complete. You will be notified with instructions when this happens!");
done.set(true);
}
}
});
sendMessage("Saving configuration...");
try {
PS.get().worlds.save(PS.get().worldsFile);
} catch (IOException ignored) {
sendMessage(" - &cFailed to save configuration.");
}
TaskManager.runTask(new Runnable() {
@Override
public void run() {
try {
boolean mv = false;
boolean mw = false;
if ((Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null) && Bukkit.getPluginManager().getPlugin("Multiverse-Core")
.isEnabled()) {
mv = true;
} else if ((Bukkit.getPluginManager().getPlugin("MultiWorld") != null) && Bukkit.getPluginManager().getPlugin("MultiWorld")
.isEnabled()) {
mw = true;
}
for (String worldName : worlds) {
World world = Bukkit.getWorld(getWorld(worldName));
if (world == null) {
sendMessage("&cInvalid world in PlotMe configuration: " + worldName);
continue;
}
String actualWorldName = world.getName();
sendMessage("Reloading generator for world: '" + actualWorldName + "'...");
if (!Bukkit.getWorlds().isEmpty() && Bukkit.getWorlds().get(0).getName().equals(worldName)) {
sendMessage("&cYou need to stop the server to reload this world properly");
} else {
PS.get().removePlotAreas(actualWorldName);
if (mv) {
// unload world with MV
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mv unload " + actualWorldName);
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
// load world with MV
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(),
"mv import " + actualWorldName + " normal -g " + PS.imp().getPluginName());
} else if (mw) {
// unload world with MW
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mw unload " + actualWorldName);
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
// load world with MW
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(),
"mw create " + actualWorldName + " plugin:" + PS.imp().getPluginName());
} else {
// Load using Bukkit API
// - User must set generator manually
Bukkit.getServer().unloadWorld(world, true);
World myWorld = WorldCreator.name(actualWorldName).generator(new BukkitPlotGenerator(PS.get().IMP.getDefaultGenerator())).createWorld();
myWorld.save();
}
}
}
} catch (CommandException e) {
e.printStackTrace();
}
if (done.get()) {
done();
sendMessage("&aDatabase conversion is now complete!");
PS.debug("&c - Stop the server");
PS.debug("&c - Disable 'plotme-converter' and 'plotme-convert.cache-uuids' in the settings.yml");
PS.debug("&c - Correct any generator settings that haven't copied to 'settings.yml' properly");
PS.debug("&c - Start the server");
} else {
sendMessage("&cPlease wait until database conversion is complete. You will be notified with instructions when this happens!");
done.set(true);
}
}
});
} catch (InterruptedException | SQLException e) {
e.printStackTrace();
PS.debug("&/end/");
}
return true;
}
public void done() {
PS.get().setPlots(DBFunc.getPlots());
}
}

View File

@ -0,0 +1,194 @@
package com.plotsquared.bukkit.database.plotme;
import com.intellectualcrafters.configuration.file.FileConfiguration;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.database.DBFunc;
import com.intellectualcrafters.plot.database.SQLite;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.StringWrapper;
import com.intellectualcrafters.plot.util.UUIDHandler;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.UUID;
public class PlotMeConnector_017 extends APlotMeConnector {
private String plugin;
@Override
public Connection getPlotMeConnection(String plugin, FileConfiguration plotConfig, String dataFolder) {
this.plugin = plugin.toLowerCase();
try {
if (plotConfig.getBoolean("usemySQL")) {
String user = plotConfig.getString("mySQLuname");
String password = plotConfig.getString("mySQLpass");
String con = plotConfig.getString("mySQLconn");
return DriverManager.getConnection(con, user, password);
} else {
File file = new File(dataFolder + File.separator + "plotmecore.db");
if (file.exists()) {
return new SQLite(file).openConnection();
}
return new SQLite(new File(dataFolder + File.separator + "plots.db")).openConnection();
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@Override
public HashMap<String, HashMap<PlotId, Plot>> getPlotMePlots(Connection connection) throws SQLException {
ResultSet resultSet;
PreparedStatement statement;
HashMap<String, Integer> plotWidth = new HashMap<>();
HashMap<String, Integer> roadWidth = new HashMap<>();
HashMap<Integer, Plot> plots = new HashMap<>();
HashMap<String, HashMap<PlotId, boolean[]>> merges = new HashMap<>();
try {
statement = connection.prepareStatement("SELECT * FROM `" + this.plugin + "core_plots`");
resultSet = statement.executeQuery();
} catch (SQLException e) {
PS.debug("========= Table does not exist =========");
e.printStackTrace();
PS.debug("=======================================");
PS.debug("&8 - &7The database does not match the version specified in the PlotMe config");
PS.debug("&8 - &7Please correct this, or if you are unsure, the most common is 0.16.3");
return null;
}
boolean checkUUID = DBFunc.hasColumn(resultSet, "ownerID");
boolean merge = !"plotme".equals(this.plugin) && Settings.Enabled_Components.PLOTME_CONVERTER;
while (resultSet.next()) {
int key = resultSet.getInt("plot_id");
PlotId id = new PlotId(resultSet.getInt("plotX"), resultSet.getInt("plotZ"));
String name = resultSet.getString("owner");
String world = LikePlotMeConverter.getWorld(resultSet.getString("world"));
if (!plots.containsKey(world) && merge) {
int plot = PS.get().worlds.getInt("worlds." + world + ".plot.size");
int path = PS.get().worlds.getInt("worlds." + world + ".road.width");
plotWidth.put(world, plot);
roadWidth.put(world, path);
merges.put(world, new HashMap<PlotId, boolean[]>());
}
if (merge) {
int tx = resultSet.getInt("topX");
int tz = resultSet.getInt("topZ");
int bx = resultSet.getInt("bottomX") - 1;
int bz = resultSet.getInt("bottomZ") - 1;
int path = roadWidth.get(world);
int plot = plotWidth.get(world);
Location top = getPlotTopLocAbs(path, plot, id);
Location bot = getPlotBottomLocAbs(path, plot, id);
if (tx > top.getX()) {
setMerged(merges, world, id, 1);
}
if (tz > top.getZ()) {
setMerged(merges, world, id, 2);
}
if (bx < bot.getX()) {
setMerged(merges, world, id, 3);
}
if (bz > bot.getZ()) {
setMerged(merges, world, id, 0);
}
}
UUID owner = UUIDHandler.getUUID(name, null);
if (owner == null) {
if (name.equals("*")) {
owner = DBFunc.everyone;
} else {
if (checkUUID) {
byte[] bytes = resultSet.getBytes("ownerid");
if (bytes != null) {
owner = UUID.nameUUIDFromBytes(bytes);
UUIDHandler.add(new StringWrapper(name), owner);
}
}
if (owner == null) {
PS.log("&cCould not identify owner for plot: " + id + " -> '" + name + '\'');
continue;
}
}
} else {
UUIDHandler.add(new StringWrapper(name), owner);
}
Plot plot = new Plot(PlotArea.createGeneric(world), id, owner);
plots.put(key, plot);
}
for (Plot plot : plots.values()) {
HashMap<PlotId, boolean[]> mergeMap = merges.get(plot.getWorldName());
if (mergeMap != null) {
if (mergeMap.containsKey(plot.getId())) {
plot.setMerged(mergeMap.get(plot.getId()));
}
}
}
resultSet.close();
statement.close();
try {
PS.log(" - " + this.plugin + "core_denied");
statement = connection.prepareStatement("SELECT * FROM `" + this.plugin + "core_denied`");
resultSet = statement.executeQuery();
while (resultSet.next()) {
int key = resultSet.getInt("plot_id");
Plot plot = plots.get(key);
if (plot == null) {
PS.log("&6Denied (" + key + ") references deleted plot; ignoring entry.");
continue;
}
UUID denied = UUID.fromString(resultSet.getString("player"));
plot.getDenied().add(denied);
}
PS.log(" - " + this.plugin + "core_allowed");
statement = connection.prepareStatement("SELECT * FROM `" + this.plugin + "core_allowed`");
resultSet = statement.executeQuery();
while (resultSet.next()) {
int key = resultSet.getInt("plot_id");
Plot plot = plots.get(key);
if (plot == null) {
PS.log("&6Allowed (" + key + ") references deleted plot; ignoring entry.");
continue;
}
UUID allowed = UUID.fromString(resultSet.getString("player"));
plot.getTrusted().add(allowed);
}
resultSet.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
HashMap<String, HashMap<PlotId, Plot>> processed = new HashMap<>();
for (Plot plot : plots.values()) {
HashMap<PlotId, Plot> map = processed.get(plot.getWorldName());
if (map == null) {
map = new HashMap<>();
processed.put(plot.getWorldName(), map);
}
map.put(plot.getId(), plot);
}
return processed;
}
@Override
public boolean accepts(String version) {
if (version == null) {
return false;
}
return !PS.get().canUpdate(version, "0.17");
}
}

View File

@ -0,0 +1,66 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.flag.Flag;
import com.intellectualcrafters.plot.object.PlotCluster;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Called when a flag is removed from a plot.
*/
public class ClusterFlagRemoveEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final PlotCluster cluster;
private final Flag flag;
private boolean cancelled;
/**
* PlotFlagRemoveEvent: Called when a flag is removed from a plot.
*
* @param flag Flag that was removed
* @param cluster PlotCluster from which the flag was removed
*/
public ClusterFlagRemoveEvent(Flag flag, PlotCluster cluster) {
this.cluster = cluster;
this.flag = flag;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the cluster involved.
*
* @return PlotCluster
*/
public PlotCluster getCluster() {
return this.cluster;
}
/**
* Get the flag involved.
*
* @return Flag
*/
public Flag getFlag() {
return this.flag;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean b) {
this.cancelled = b;
}
}

View File

@ -0,0 +1,62 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
public class PlayerClaimPlotEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Plot plot;
private final boolean auto;
private boolean cancelled;
/**
* PlayerClaimPlotEvent: Called when a plot is claimed.
*
* @param player Player that claimed the plot
* @param plot Plot that was claimed
*/
public PlayerClaimPlotEvent(Player player, Plot plot, boolean auto) {
super(player);
this.plot = plot;
this.auto = auto;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the plot involved
*
* @return Plot
*/
public Plot getPlot() {
return this.plot;
}
/**
* @return true if it was an automated claim, else false
*/
public boolean wasAuto() {
return this.auto;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean b) {
this.cancelled = b;
}
}

View File

@ -0,0 +1,41 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
public class PlayerEnterPlotEvent extends PlayerEvent {
private static final HandlerList handlers = new HandlerList();
private final Plot plot;
/**
* Called when a player leaves a plot.
*
* @param player Player that entered the plot
* @param plot Plot that was entered
*/
public PlayerEnterPlotEvent(Player player, Plot plot) {
super(player);
this.plot = plot;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the plot involved.
*
* @return Plot
*/
public Plot getPlot() {
return this.plot;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -0,0 +1,45 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
/**
*/
public class PlayerLeavePlotEvent extends PlayerEvent {
private static final HandlerList handlers = new HandlerList();
private final Plot plot;
/**
* PlayerLeavePlotEvent: Called when a player leaves a plot
*
* @param player Player that left the plot
* @param plot Plot that was left
*/
public PlayerLeavePlotEvent(Player player, Plot plot) {
super(player);
this.plot = plot;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the plot involved
*
* @return Plot
*/
public Plot getPlot() {
return this.plot;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -0,0 +1,66 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import java.util.UUID;
public class PlayerPlotDeniedEvent extends PlotEvent {
private static final HandlerList handlers = new HandlerList();
private final Player initiator;
private final boolean added;
private final UUID player;
/**
* PlayerPlotDeniedEvent: Called when the denied UUID list is modified for a plot.
*
* @param initiator Player that initiated the event
* @param plot Plot in which the event occurred
* @param player Player that was denied/un-denied
* @param added true of add to deny list, false if removed
*/
public PlayerPlotDeniedEvent(Player initiator, Plot plot, UUID player, boolean added) {
super(plot);
this.initiator = initiator;
this.added = added;
this.player = player;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* If a user was added.
*
* @return boolean
*/
public boolean wasAdded() {
return this.added;
}
/**
* The player added/removed.
*
* @return UUID
*/
public UUID getPlayer() {
return this.player;
}
/**
* The player initiating the action.
*
* @return Player
*/
public Player getInitiator() {
return this.initiator;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -0,0 +1,70 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import java.util.UUID;
/**
*/
public class PlayerPlotHelperEvent extends PlotEvent {
private static final HandlerList handlers = new HandlerList();
private final Player initiator;
private final boolean added;
private final UUID player;
/**
* PlayerPlotHelperEvent: Called when a plot helper is added/removed
*
* @param initiator Player that initiated the event
* @param plot Plot in which the event occurred
* @param player Player that was added/removed from the helper list
* @param added true of the player was added, false if the player was removed
*/
public PlayerPlotHelperEvent(Player initiator, Plot plot, UUID player, boolean added) {
super(plot);
this.initiator = initiator;
this.added = added;
this.player = player;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* If a player was added
*
* @return boolean
*/
public boolean wasAdded() {
return this.added;
}
/**
* The UUID added/removed
*
* @return UUID
*/
public UUID getPlayer() {
return this.player;
}
/**
* The player initiating the action
*
* @return Player
*/
public Player getInitiator() {
return this.initiator;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -0,0 +1,70 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import java.util.UUID;
/**
*/
public class PlayerPlotTrustedEvent extends PlotEvent {
private static final HandlerList handlers = new HandlerList();
private final Player initiator;
private final boolean added;
private final UUID player;
/**
* PlayerPlotTrustedEvent: Called when a plot trusted user is added/removed
*
* @param initiator Player that initiated the event
* @param plot Plot in which the event occurred
* @param player Player that was added/removed from the trusted list
* @param added true of the player was added, false if the player was removed
*/
public PlayerPlotTrustedEvent(Player initiator, Plot plot, UUID player, boolean added) {
super(plot);
this.initiator = initiator;
this.added = added;
this.player = player;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* If a player was added
*
* @return boolean
*/
public boolean wasAdded() {
return this.added;
}
/**
* The UUID added/removed
*
* @return UUID
*/
public UUID getPlayer() {
return this.player;
}
/**
* The player initiating the action
*
* @return Player
*/
public Player getInitiator() {
return this.initiator;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -0,0 +1,72 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
/**
* Called when a player teleports to a plot
*
*/
public class PlayerTeleportToPlotEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Location from;
private final Plot plot;
private boolean cancelled;
/**
* PlayerTeleportToPlotEvent: Called when a player teleports to a plot
*
* @param player That was teleported
* @param from Start location
* @param plot Plot to which the player was teleported
*/
public PlayerTeleportToPlotEvent(Player player, Location from, Plot plot) {
super(player);
this.from = from;
this.plot = plot;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
/**
* Get the from location
*
* @return Location
*/
public Location getFrom() {
return this.from;
}
/**
* Get the plot involved
*
* @return Plot
*/
public Plot getPlot() {
return this.plot;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -0,0 +1,56 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* Called when a plot is cleared
*
*/
public class PlotClearEvent extends PlotEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
public PlotClearEvent(Plot plot) {
super(plot);
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the PlotId.
*
* @return PlotId
*/
public PlotId getPlotId() {
return getPlot().getId();
}
/**
* Get the world name.
*
* @return String
*/
public String getWorld() {
return getPlot().getWorldName();
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean b) {
this.cancelled = b;
}
}

View File

@ -0,0 +1,56 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId;
import org.bukkit.event.HandlerList;
/**
* Called when a plot component is set
*
*/
public class PlotComponentSetEvent extends PlotEvent {
private static final HandlerList handlers = new HandlerList();
private final String component;
public PlotComponentSetEvent(Plot plot, String component) {
super(plot);
this.component = component;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the PlotId
*
* @return PlotId
*/
public PlotId getPlotId() {
return getPlot().getId();
}
/**
* Get the world name
*
* @return String
*/
public String getWorld() {
return getPlot().getWorldName();
}
/**
* Get the component which was set
*
* @return Component name
*/
public String getComponent() {
return this.component;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -0,0 +1,45 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId;
import org.bukkit.event.HandlerList;
/**
* Called when a plot is deleted
*
*/
public class PlotDeleteEvent extends PlotEvent {
private static final HandlerList handlers = new HandlerList();
public PlotDeleteEvent(Plot plot) {
super(plot);
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the PlotId
*
* @return PlotId
*/
public PlotId getPlotId() {
return getPlot().getId();
}
/**
* Get the world name
*
* @return String
*/
public String getWorld() {
return getPlot().getWorldName();
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -1,19 +1,18 @@
package com.plotsquared.bukkit.events; package com.plotsquared.bukkit.events;
import org.bukkit.event.Event;
import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.event.Event;
public abstract class PlotEvent extends Event { public abstract class PlotEvent extends Event {
private final Plot plot; private final Plot plot;
public PlotEvent(final Plot plot) { public PlotEvent(Plot plot) {
this.plot = plot; this.plot = plot;
} }
public final Plot getPlot() { public final Plot getPlot() {
return plot; return this.plot;
} }
} }

View File

@ -0,0 +1,56 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.flag.Flag;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* Called when a Flag is added to a plot.
*
*/
public class PlotFlagAddEvent extends PlotEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Flag flag;
private boolean cancelled;
/**
* PlotFlagAddEvent: Called when a Flag is added to a plot.
*
* @param flag Flag that was added
* @param plot Plot to which the flag was added
*/
public PlotFlagAddEvent(Flag flag, Plot plot) {
super(plot);
this.flag = flag;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the flag involved.
*
* @return Flag
*/
public Flag getFlag() {
return this.flag;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public final boolean isCancelled() {
return this.cancelled;
}
@Override
public final void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -0,0 +1,56 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.flag.Flag;
import com.intellectualcrafters.plot.object.Plot;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* Called when a flag is removed from a plot
*
*/
public class PlotFlagRemoveEvent extends PlotEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Flag flag;
private boolean cancelled;
/**
* PlotFlagRemoveEvent: Called when a flag is removed from a plot
*
* @param flag Flag that was removed
* @param plot Plot from which the flag was removed
*/
public PlotFlagRemoveEvent(Flag flag, Plot plot) {
super(plot);
this.flag = flag;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the flag involved
*
* @return Flag
*/
public Flag getFlag() {
return this.flag;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public final boolean isCancelled() {
return this.cancelled;
}
@Override
public final void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -0,0 +1,62 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId;
import org.bukkit.World;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import java.util.ArrayList;
public class PlotMergeEvent extends PlotEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final ArrayList<PlotId> plots;
private final World world;
private boolean cancelled;
/**
* PlotMergeEvent: Called when plots are merged
*
* @param world World in which the event occurred
* @param plot Plot that was merged
* @param plots A list of plots involved in the event
*/
public PlotMergeEvent(World world, Plot plot, ArrayList<PlotId> plots) {
super(plot);
this.world = world;
this.plots = plots;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the plots being added.
*
* @return Plot
*/
public ArrayList<PlotId> getPlots() {
return this.plots;
}
public World getWorld() {
return this.world;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean b) {
this.cancelled = b;
}
}

View File

@ -1,22 +1,17 @@
package com.plotsquared.bukkit.events; package com.plotsquared.bukkit.events;
import org.bukkit.event.HandlerList;
import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.object.Rating; import com.intellectualcrafters.plot.object.Rating;
import org.bukkit.event.HandlerList;
/**
* Created 2015-07-13 for PlotSquaredGit
*
*/
public class PlotRateEvent extends PlotEvent { public class PlotRateEvent extends PlotEvent {
private static HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private final PlotPlayer rater; private final PlotPlayer rater;
private Rating rating; private Rating rating;
public PlotRateEvent(final PlotPlayer rater, final Rating rating, final Plot plot) { public PlotRateEvent(PlotPlayer rater, Rating rating, Plot plot) {
super(plot); super(plot);
this.rater = rater; this.rater = rater;
this.rating = rating; this.rating = rating;
@ -27,15 +22,15 @@ public class PlotRateEvent extends PlotEvent {
} }
public PlotPlayer getRater() { public PlotPlayer getRater() {
return rater; return this.rater;
}
public void setRating(final Rating rating) {
this.rating = rating;
} }
public Rating getRating() { public Rating getRating() {
return rating; return this.rating;
}
public void setRating(Rating rating) {
this.rating = rating;
} }
@Override @Override

View File

@ -0,0 +1,67 @@
package com.plotsquared.bukkit.events;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotId;
import org.bukkit.World;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.ArrayList;
public class PlotUnlinkEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final ArrayList<PlotId> plots;
private final World world;
private final PlotArea area;
private boolean cancelled;
/**
* Called when a mega-plot is unlinked.
*
* @param world World in which the event occurred
* @param plots Plots that are involved in the event
*/
public PlotUnlinkEvent(World world, PlotArea area, ArrayList<PlotId> plots) {
this.plots = plots;
this.world = world;
this.area = area;
}
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Get the plots involved.
*
* @return The {@link PlotId}'s of the plots involved
*/
public ArrayList<PlotId> getPlots() {
return this.plots;
}
public World getWorld() {
return this.world;
}
public PlotArea getArea() {
return this.area;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean b) {
this.cancelled = b;
}
}

View File

@ -11,8 +11,6 @@ public class BukkitAugmentedGenerator extends BlockPopulator {
private static BukkitAugmentedGenerator generator; private static BukkitAugmentedGenerator generator;
private BukkitAugmentedGenerator() {}
public static BukkitAugmentedGenerator get(World world) { public static BukkitAugmentedGenerator get(World world) {
for (BlockPopulator populator : world.getPopulators()) { for (BlockPopulator populator : world.getPopulators()) {
if (populator instanceof BukkitAugmentedGenerator) { if (populator instanceof BukkitAugmentedGenerator) {
@ -27,7 +25,7 @@ public class BukkitAugmentedGenerator extends BlockPopulator {
} }
@Override @Override
public void populate(final World world, Random r, final Chunk chunk) { public void populate(World world, Random r, Chunk chunk) {
AugmentedUtils.generate(world.getName(), chunk.getX(), chunk.getZ(), null); AugmentedUtils.generate(world.getName(), chunk.getX(), chunk.getZ(), null);
} }
} }

View File

@ -1,40 +1,11 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// PlotSquared - A plot manager and world generator for the Bukkit API /
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
// /
// This program is free software; you can redistribute it and/or modify /
// it under the terms of the GNU General Public License as published by /
// the Free Software Foundation; either version 3 of the License, or /
// (at your option) any later version. /
// /
// This program is distributed in the hope that it will be useful, /
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
// GNU General Public License for more details. /
// /
// You should have received a copy of the GNU General Public License /
// along with this program; if not, write to the Free Software Foundation, /
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
// /
// You can contact us via: support@intellectualsites.com /
////////////////////////////////////////////////////////////////////////////////////////////////////
package com.plotsquared.bukkit.generator; package com.plotsquared.bukkit.generator;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.generator.GeneratorWrapper; import com.intellectualcrafters.plot.generator.GeneratorWrapper;
import com.intellectualcrafters.plot.generator.HybridGen;
import com.intellectualcrafters.plot.generator.IndependentPlotGenerator; import com.intellectualcrafters.plot.generator.IndependentPlotGenerator;
import com.intellectualcrafters.plot.object.ChunkLoc;
import com.intellectualcrafters.plot.object.ChunkWrapper;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.PlotArea; import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotId; import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.PlotManager; import com.intellectualcrafters.plot.object.PlotManager;
@ -42,37 +13,70 @@ import com.intellectualcrafters.plot.object.PseudoRandom;
import com.intellectualcrafters.plot.object.SetupObject; import com.intellectualcrafters.plot.object.SetupObject;
import com.intellectualcrafters.plot.util.ChunkManager; import com.intellectualcrafters.plot.util.ChunkManager;
import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.PlotChunk; import com.intellectualcrafters.plot.util.MathMan;
import com.intellectualcrafters.plot.util.SetQueue; import com.intellectualcrafters.plot.util.block.GlobalBlockQueue;
import com.plotsquared.bukkit.listeners.WorldEvents; import com.intellectualcrafters.plot.util.block.LocalBlockQueue;
import com.intellectualcrafters.plot.util.block.ScopedLocalBlockQueue;
import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.bukkit.util.block.GenChunk; import com.plotsquared.bukkit.util.block.GenChunk;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrapper<ChunkGenerator> { public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrapper<ChunkGenerator> {
private final PlotChunk<Chunk> chunkSetter; private final GenChunk chunkSetter;
private final PseudoRandom random = new PseudoRandom(); private final PseudoRandom random = new PseudoRandom();
private final IndependentPlotGenerator plotGenerator; private final IndependentPlotGenerator plotGenerator;
private final List<BlockPopulator> populators = new ArrayList<>(); private List<BlockPopulator> populators;
private final ChunkGenerator platformGenerator;
private final boolean full;
private final HashMap<ChunkLoc, byte[][]> dataMap = new HashMap<>();
private boolean loaded = false; private boolean loaded = false;
private ChunkGenerator platformGenerator;
private boolean full;
public BukkitPlotGenerator(IndependentPlotGenerator generator) { public BukkitPlotGenerator(IndependentPlotGenerator generator) {
if (generator == null) {
throw new IllegalArgumentException("Generator may not be null!");
}
this.plotGenerator = generator; this.plotGenerator = generator;
this.platformGenerator = this; this.platformGenerator = this;
populators.add(new BlockPopulator() { populators = new ArrayList<>();
this.populators.add(new BlockPopulator() {
private LocalBlockQueue queue;
@Override @Override
public void populate(World world, Random r, Chunk c) { public void populate(World world, Random r, Chunk c) {
if (!(chunkSetter instanceof GenChunk)) { if (queue == null) {
PS.debug("Current PlotChunk is not relevant to population?"); queue = GlobalBlockQueue.IMP.getNewQueue(world.getName(), false);
PS.stacktrace();
return;
} }
GenChunk result = (GenChunk) chunkSetter; ChunkLoc loc = new ChunkLoc(c.getX(), c.getZ());
if (result.result_data != null) { byte[][] resultData;
for (int i = 0; i < result.result_data.length; i++) { if (!BukkitPlotGenerator.this.dataMap.containsKey(loc)) {
byte[] section = result.result_data[i]; GenChunk result = BukkitPlotGenerator.this.chunkSetter;
// Set the chunk location
result.setChunk(c);
// Set the result data
result.result = new short[16][];
result.result_data = new byte[16][];
result.grid = null;
result.cd = null;
// Catch any exceptions (as exceptions usually thrown)
generate(world, loc.x, loc.z, result);
resultData = result.result_data;
} else {
resultData = BukkitPlotGenerator.this.dataMap.remove(loc);
}
if (resultData != null) {
for (int i = 0; i < resultData.length; i++) {
byte[] section = resultData[i];
if (section == null) { if (section == null) {
continue; continue;
} }
@ -84,9 +88,16 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
} }
} }
} }
BukkitPlotGenerator.this.random.state = c.getX() << 16 | c.getZ() & 0xFFFF;
PlotArea area = PS.get().getPlotArea(world.getName(), null);
ChunkWrapper wrap = new ChunkWrapper(area.worldname, c.getX(), c.getZ());
ScopedLocalBlockQueue chunk = queue.getForChunk(wrap.x, wrap.z);
if (BukkitPlotGenerator.this.plotGenerator.populateChunk(chunk, area, BukkitPlotGenerator.this.random)) {
queue.flush();
}
} }
}); });
chunkSetter = new GenChunk(null, null); this.chunkSetter = new GenChunk(null, null);
this.full = true; this.full = true;
MainUtil.initCache(); MainUtil.initCache();
} }
@ -96,10 +107,9 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
throw new IllegalArgumentException("ChunkGenerator: " + cg.getClass().getName() + " is already a BukkitPlotGenerator!"); throw new IllegalArgumentException("ChunkGenerator: " + cg.getClass().getName() + " is already a BukkitPlotGenerator!");
} }
this.full = false; this.full = false;
WorldEvents.lastWorld = world; PS.debug("BukkitPlotGenerator does not fully support: " + cg);
PS.get().debug("BukkitPlotGenerator does not fully support: " + cg); this.platformGenerator = cg;
platformGenerator = cg; this.plotGenerator = new IndependentPlotGenerator() {
plotGenerator = new IndependentPlotGenerator() {
@Override @Override
public void processSetup(SetupObject setup) {} public void processSetup(SetupObject setup) {}
@ -108,7 +118,7 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
@Override @Override
public PlotManager getNewPlotManager() { public PlotManager getNewPlotManager() {
return new HybridGen().getNewPlotManager(); return PS.get().IMP.getDefaultGenerator().getNewPlotManager();
} }
@Override @Override
@ -118,17 +128,20 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
@Override @Override
public PlotArea getNewPlotArea(String world, String id, PlotId min, PlotId max) { public PlotArea getNewPlotArea(String world, String id, PlotId min, PlotId max) {
return new HybridGen().getNewPlotArea(world, id, min, max); return PS.get().IMP.getDefaultGenerator().getNewPlotArea(world, id, min, max);
} }
@Override @Override
public void generateChunk(final PlotChunk<?> result, final PlotArea settings, final PseudoRandom random) { public void generateChunk(final ScopedLocalBlockQueue result, PlotArea settings, PseudoRandom random) {
World w = BukkitUtil.getWorld(world); World w = BukkitUtil.getWorld(world);
Random r = new Random(result.getChunkWrapper().hashCode()); Location min = result.getMin();
int cx = min.getX() >> 4;
int cz = min.getZ() >> 4;
Random r = new Random(MathMan.pair((short) cx, (short) cz));
BiomeGrid grid = new BiomeGrid() { BiomeGrid grid = new BiomeGrid() {
@Override @Override
public void setBiome(int x, int z, Biome biome) { public void setBiome(int x, int z, Biome biome) {
result.setBiome(x, z, biome.ordinal()); result.setBiome(x, z, biome.name());
} }
@Override @Override
@ -138,14 +151,13 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
}; };
try { try {
// ChunkData will spill a bit // ChunkData will spill a bit
ChunkData data = cg.generateChunkData(w, r, result.getX(), result.getZ(), grid); ChunkData data = cg.generateChunkData(w, r, cx, cz, grid);
if (data != null) { if (data != null) {
return; return;
} }
} } catch (Throwable ignored) {}
catch (Throwable e) {}
// Populator spillage // Populator spillage
short[][] tmp = cg.generateExtBlockSections(w, r, result.getX(), result.getZ(), grid); short[][] tmp = cg.generateExtBlockSections(w, r, cx, cz, grid);
if (tmp != null) { if (tmp != null) {
for (int i = 0; i < tmp.length; i++) { for (int i = 0; i < tmp.length; i++) {
short[] section = tmp[i]; short[] section = tmp[i];
@ -170,14 +182,11 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
} }
} }
for (BlockPopulator populator : cg.getDefaultPopulators(w)) { for (BlockPopulator populator : cg.getDefaultPopulators(w)) {
populator.populate(w, r, (Chunk) result.getChunk()); populator.populate(w, r, w.getChunkAt(cx, cz));
} }
} }
}; };
chunkSetter = new GenChunk(null, SetQueue.IMP.new ChunkWrapper(world, 0, 0)); this.chunkSetter = new GenChunk(null, new ChunkWrapper(world, 0, 0));
if (cg != null) {
populators.addAll(cg.getDefaultPopulators(BukkitUtil.getWorld(world)));
}
MainUtil.initCache(); MainUtil.initCache();
} }
@ -188,24 +197,24 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
@Override @Override
public boolean isFull() { public boolean isFull() {
return full; return this.full;
} }
@Override @Override
public IndependentPlotGenerator getPlotGenerator() { public IndependentPlotGenerator getPlotGenerator() {
return plotGenerator; return this.plotGenerator;
} }
@Override @Override
public ChunkGenerator getPlatformGenerator() { public ChunkGenerator getPlatformGenerator() {
return platformGenerator; return this.platformGenerator;
} }
@Override @Override
public List<BlockPopulator> getDefaultPopulators(final World world) { public List<BlockPopulator> getDefaultPopulators(World world) {
try { try {
if (!loaded) { if (!this.loaded) {
final String name = WorldEvents.getName(world); String name = world.getName();
PS.get().loadWorld(name, this); PS.get().loadWorld(name, this);
Set<PlotArea> areas = PS.get().getPlotAreas(name); Set<PlotArea> areas = PS.get().getPlotAreas(name);
if (!areas.isEmpty()) { if (!areas.isEmpty()) {
@ -226,32 +235,39 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
world.setWaterAnimalSpawnLimit(-1); world.setWaterAnimalSpawnLimit(-1);
} }
} }
loaded = true; this.loaded = true;
} }
} catch (final Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return populators; ArrayList<BlockPopulator> toAdd = new ArrayList<>();
List<BlockPopulator> existing = world.getPopulators();
if (populators == null && platformGenerator != null) {
populators = new ArrayList<>(platformGenerator.getDefaultPopulators(world));
}
for (BlockPopulator populator : this.populators) {
if (!existing.contains(populator)) {
toAdd.add(populator);
}
}
return toAdd;
} }
@Override @Override
public ChunkData generateChunkData(World world, Random random, int cx, int cz, BiomeGrid grid) { public ChunkData generateChunkData(World world, Random random, int cx, int cz, BiomeGrid grid) {
if (!(chunkSetter instanceof GenChunk)) { GenChunk result = this.chunkSetter;
PS.debug("Current PlotChunk is not relevant to generation?");
PS.stacktrace();
return null;
}
GenChunk result = (GenChunk) chunkSetter;
// Set the chunk location // Set the chunk location
result.setChunkWrapper(SetQueue.IMP.new ChunkWrapper(world.getName(), cx, cz)); result.setChunk(new ChunkWrapper(world.getName(), cx, cz));
// Set the result data // Set the result data
result.cd = createChunkData(world); result.cd = createChunkData(world);
result.grid = grid; result.grid = grid;
// Catch any exceptions (as exceptions usually thrown result.result = null;
result.result_data = null;
// Catch any exceptions (as exceptions usually thrown)
try { try {
// Fill the result data if necessary // Fill the result data if necessary
if (platformGenerator != this) { if (this.platformGenerator != this) {
return platformGenerator.generateChunkData(world, random, cx, cz, grid); return this.platformGenerator.generateChunkData(world, random, cx, cz, grid);
} else { } else {
generate(world, cx, cz, result); generate(world, cx, cz, result);
} }
@ -262,46 +278,48 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
return result.cd; return result.cd;
} }
public void generate(World world, int cx, int cz, GenChunk result) { public void generate(World world, int cx, int cz, ScopedLocalBlockQueue result) {
// Load if improperly loaded // Load if improperly loaded
if (!loaded) { if (!this.loaded) {
final String name = WorldEvents.getName(world); String name = world.getName();
PS.get().loadWorld(name, this); PS.get().loadWorld(name, this);
loaded = true; this.loaded = true;
} }
// Set random seed // Set random seed
this.random.state = (cx << 16) | (cz & 0xFFFF); this.random.state = cx << 16 | cz & 0xFFFF;
// Process the chunk // Process the chunk
result.modified = false; if (ChunkManager.preProcessChunk(result)) {
ChunkManager.preProcessChunk(result);
if (result.modified) {
return; return;
} }
PlotArea area = PS.get().getPlotArea(world.getName(), null); PlotArea area = PS.get().getPlotArea(world.getName(), null);
plotGenerator.generateChunk(chunkSetter, area, this.random); try {
this.plotGenerator.generateChunk(this.chunkSetter, area, this.random);
} catch (Throwable e) {
// Recover from generator error
e.printStackTrace();
}
ChunkManager.postProcessChunk(result); ChunkManager.postProcessChunk(result);
return;
} }
@Override @Override
public short[][] generateExtBlockSections(final World world, final Random r, final int cx, final int cz, final BiomeGrid grid) { public short[][] generateExtBlockSections(World world, Random r, int cx, int cz, BiomeGrid grid) {
if (!(chunkSetter instanceof GenChunk)) { GenChunk result = this.chunkSetter;
PS.stacktrace();
return new short[16][];
}
GenChunk result = (GenChunk) chunkSetter;
// Set the chunk location // Set the chunk location
result.setChunkWrapper(SetQueue.IMP.new ChunkWrapper(world.getName(), cx, cz)); result.setChunk(new ChunkWrapper(world.getName(), cx, cz));
// Set the result data // Set the result data
result.result = new short[16][]; result.result = new short[16][];
result.result_data = new byte[16][]; result.result_data = new byte[16][];
// Catch any exceptions (as exceptions usually thrown result.grid = grid;
result.cd = null;
// Catch any exceptions (as exceptions usually thrown)
try { try {
// Fill the result data // Fill the result data
if (platformGenerator != this) { if (this.platformGenerator != this) {
return platformGenerator.generateExtBlockSections(world, r, cx, cz, grid); return this.platformGenerator.generateExtBlockSections(world, r, cx, cz, grid);
} else { } else {
generate(world, cx, cz, result); generate(world, cx, cz, result);
this.dataMap.put(new ChunkLoc(cx, cz), result.result_data);
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@ -311,19 +329,27 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
} }
/** /**
* Allow spawning everywhere * Allow spawning everywhere.
* @param world Ignored
* @param x Ignored
* @param z Ignored
* @return always true
*/ */
@Override @Override
public boolean canSpawn(final World world, final int x, final int z) { public boolean canSpawn(World world, int x, int z) {
return true; return true;
} }
@Override @Override
public String toString() { public String toString() {
if (platformGenerator == this) { if (this.platformGenerator == this) {
return "" + plotGenerator; return this.plotGenerator.getName();
}
if (this.platformGenerator == null) {
return "null";
} else {
return this.platformGenerator.getClass().getName();
} }
return platformGenerator == null ? "null" : platformGenerator.getClass().getName();
} }
@Override @Override
@ -331,6 +357,6 @@ public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrap
if (obj == null) { if (obj == null) {
return false; return false;
} }
return (toString().equals(obj.toString()) || toString().equals(obj.getClass().getName())); return toString().equals(obj.toString()) || toString().equals(obj.getClass().getName());
} }
} }

View File

@ -0,0 +1,288 @@
package com.plotsquared.bukkit.listeners;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefField;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
import com.intellectualcrafters.plot.util.TaskManager;
import java.lang.reflect.Method;
import java.util.HashSet;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
public class ChunkListener implements Listener {
private RefMethod methodGetHandleChunk;
private RefField mustSave;
private Chunk lastChunk;
public ChunkListener() {
if (Settings.Chunk_Processor.AUTO_TRIM) {
try {
RefClass classChunk = getRefClass("{nms}.Chunk");
RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
this.mustSave = classChunk.getField("mustSave");
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
} catch (Throwable ignored) {
PS.debug(PS.imp().getPluginName() + "/Server not compatible for chunk processor trim/gc");
Settings.Chunk_Processor.AUTO_TRIM = false;
}
}
if (!Settings.Chunk_Processor.AUTO_TRIM) {
return;
}
for (World world : Bukkit.getWorlds()) {
world.setAutoSave(false);
}
TaskManager.runTaskRepeat(new Runnable() {
@Override
public void run() {
try {
HashSet<Chunk> toUnload = new HashSet<>();
for (World world : Bukkit.getWorlds()) {
String worldName = world.getName();
if (!PS.get().hasPlotArea(worldName)) {
continue;
}
Object w = world.getClass().getDeclaredMethod("getHandle").invoke(world);
Object chunkMap = w.getClass().getDeclaredMethod("getPlayerChunkMap").invoke(w);
Method methodIsChunkInUse = chunkMap.getClass().getDeclaredMethod("isChunkInUse", int.class, int.class);
Chunk[] chunks = world.getLoadedChunks();
for (Chunk chunk : chunks) {
if ((boolean) methodIsChunkInUse.invoke(chunkMap, chunk.getX(), chunk.getZ())) {
continue;
}
int x = chunk.getX();
int z = chunk.getZ();
if (!shouldSave(worldName, x, z)) {
unloadChunk(worldName, chunk, false);
continue;
}
toUnload.add(chunk);
}
}
if (toUnload.isEmpty()) {
return;
}
long start = System.currentTimeMillis();
for (Chunk chunk : toUnload) {
if (System.currentTimeMillis() - start > 5) {
return;
}
chunk.unload(true, false);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}, 1);
}
private boolean ignoreUnload = false;
public boolean unloadChunk(String world, Chunk chunk, boolean safe) {
if (safe && shouldSave(world, chunk.getX(), chunk.getZ())) {
return false;
}
Object c = this.methodGetHandleChunk.of(chunk).call();
RefField.RefExecutor field = this.mustSave.of(c);
if ((Boolean) field.get() == true) {
field.set(false);
if (chunk.isLoaded()) {
ignoreUnload = true;
chunk.unload(false, false);
ignoreUnload = false;
}
}
return true;
}
public boolean shouldSave(String world, int X, int Z) {
int x = X << 4;
int z = Z << 4;
int x2 = x + 15;
int z2 = z + 15;
Plot plot = new Location(world, x, 1, z).getOwnedPlotAbs();
if (plot != null && plot.hasOwner()) {
return true;
}
plot = new Location(world, x2, 1, z2).getOwnedPlotAbs();
if (plot != null && plot.hasOwner()) {
return true;
}
plot = new Location(world, x2, 1, z).getOwnedPlotAbs();
if (plot != null && plot.hasOwner()) {
return true;
}
plot = new Location(world, x, 1, z2).getOwnedPlotAbs();
if (plot != null && plot.hasOwner()) {
return true;
}
plot = new Location(world, x + 7, 1, z + 7).getOwnedPlotAbs();
return plot != null && plot.hasOwner();
}
@EventHandler
public void onChunkUnload(ChunkUnloadEvent event) {
if (ignoreUnload) {
return;
}
if (Settings.Chunk_Processor.AUTO_TRIM) {
Chunk chunk = event.getChunk();
String world = chunk.getWorld().getName();
if (PS.get().hasPlotArea(world)) {
if (unloadChunk(world, chunk, true)) {
return;
}
}
}
if (processChunk(event.getChunk(), true)) {
event.setCancelled(true);
}
}
@EventHandler
public void onChunkLoad(ChunkLoadEvent event) {
processChunk(event.getChunk(), false);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onItemSpawn(ItemSpawnEvent event) {
Item entity = event.getEntity();
Chunk chunk = entity.getLocation().getChunk();
if (chunk == this.lastChunk) {
event.getEntity().remove();
event.setCancelled(true);
return;
}
if (!PS.get().hasPlotArea(chunk.getWorld().getName())) {
return;
}
Entity[] entities = chunk.getEntities();
if (entities.length > Settings.Chunk_Processor.MAX_ENTITIES) {
event.getEntity().remove();
event.setCancelled(true);
this.lastChunk = chunk;
} else {
this.lastChunk = null;
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockPhysics(BlockPhysicsEvent event) {
if (Settings.Chunk_Processor.DISABLE_PHYSICS) {
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onEntitySpawn(CreatureSpawnEvent event) {
LivingEntity entity = event.getEntity();
Chunk chunk = entity.getLocation().getChunk();
if (chunk == this.lastChunk) {
event.getEntity().remove();
event.setCancelled(true);
return;
}
if (!PS.get().hasPlotArea(chunk.getWorld().getName())) {
return;
}
Entity[] entities = chunk.getEntities();
if (entities.length > Settings.Chunk_Processor.MAX_ENTITIES) {
event.getEntity().remove();
event.setCancelled(true);
this.lastChunk = chunk;
} else {
this.lastChunk = null;
}
}
private void cleanChunk(final Chunk chunk) {
TaskManager.index.incrementAndGet();
final Integer currentIndex = TaskManager.index.get();
Integer task = TaskManager.runTaskRepeat(new Runnable() {
@Override
public void run() {
if (!chunk.isLoaded()) {
Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex));
TaskManager.tasks.remove(currentIndex);
PS.debug(C.PREFIX.s() + "&aSuccessfully processed and unloaded chunk!");
chunk.unload(true, true);
return;
}
BlockState[] tiles = chunk.getTileEntities();
if (tiles.length == 0) {
Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex));
TaskManager.tasks.remove(currentIndex);
PS.debug(C.PREFIX.s() + "&aSuccessfully processed and unloaded chunk!");
chunk.unload(true, true);
return;
}
long start = System.currentTimeMillis();
int i = 0;
while (System.currentTimeMillis() - start < 250) {
if (i >= tiles.length) {
Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex));
TaskManager.tasks.remove(currentIndex);
PS.debug(C.PREFIX.s() + "&aSuccessfully processed and unloaded chunk!");
chunk.unload(true, true);
return;
}
tiles[i].getBlock().setType(Material.AIR, false);
i++;
}
}
}, 5);
TaskManager.tasks.put(currentIndex, task);
}
public boolean processChunk(Chunk chunk, boolean unload) {
if (!PS.get().hasPlotArea(chunk.getWorld().getName())) {
return false;
}
Entity[] entities = chunk.getEntities();
BlockState[] tiles = chunk.getTileEntities();
if (entities.length > Settings.Chunk_Processor.MAX_ENTITIES) {
for (Entity ent : entities) {
if (!(ent instanceof Player)) {
ent.remove();
}
}
PS.debug(C.PREFIX.s() + "&a detected unsafe chunk and processed: " + (chunk.getX() << 4) + "," + (chunk.getX() << 4));
}
if (tiles.length > Settings.Chunk_Processor.MAX_TILES) {
if (unload) {
PS.debug(C.PREFIX.s() + "&c detected unsafe chunk: " + (chunk.getX() << 4) + "," + (chunk.getX() << 4));
cleanChunk(chunk);
return true;
}
for (BlockState tile : tiles) {
tile.getBlock().setType(Material.AIR, false);
}
}
return false;
}
}

View File

@ -0,0 +1,43 @@
package com.plotsquared.bukkit.listeners;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.flag.Flags;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.plotsquared.bukkit.util.BukkitUtil;
import org.bukkit.entity.Entity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntitySpawnEvent;
public class EntitySpawnListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void creatureSpawnEvent(EntitySpawnEvent event) {
Entity entity = event.getEntity();
Location location = BukkitUtil.getLocation(entity.getLocation());
PlotArea area = location.getPlotArea();
if (area == null) {
return;
}
Plot plot = area.getOwnedPlotAbs(location);
if (plot == null) {
if (!area.MOB_SPAWNING) {
if (event.getEntityType().isAlive() || !area.MISC_SPAWN_UNOWNED) {
event.setCancelled(true);
}
}
return;
}
if (Settings.Done.RESTRICT_BUILDING && plot.hasFlag(Flags.DONE)) {
event.setCancelled(true);
}
switch (entity.getType()) {
case ENDER_CRYSTAL:
if (PlayerEvents.checkEntity(entity, plot)) {
event.setCancelled(true);
}
}
}
}

View File

@ -0,0 +1,98 @@
package com.plotsquared.bukkit.listeners;
import com.google.common.collect.Iterables;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.flag.Flags;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.Permissions;
import com.plotsquared.bukkit.object.BukkitPlayer;
import com.plotsquared.bukkit.util.BukkitUtil;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
public class ForceFieldListener {
private static Set<PlotPlayer> getNearbyPlayers(Player player, Plot plot) {
Set<PlotPlayer> players = new HashSet<>();
for (Player nearPlayer : Iterables.filter(player.getNearbyEntities(5d, 5d, 5d),Player.class)) {
PlotPlayer plotPlayer;
if ((plotPlayer = BukkitUtil.getPlayer(nearPlayer)) == null || !plot.equals(plotPlayer.getCurrentPlot())) {
continue;
}
if (!plot.isAdded(plotPlayer.getUUID())) {
players.add(plotPlayer);
}
}
return players;
}
private static PlotPlayer hasNearbyPermitted(Player player, Plot plot) {
for (Player nearPlayer : Iterables.filter(player.getNearbyEntities(5d, 5d, 5d),Player.class)) {
PlotPlayer plotPlayer;
if ((plotPlayer = BukkitUtil.getPlayer(nearPlayer)) == null || !plot.equals(plotPlayer.getCurrentPlot())) {
continue;
}
if (plot.isAdded(plotPlayer.getUUID())) {
return plotPlayer;
}
}
return null;
}
private static Vector calculateVelocity(PlotPlayer player, PlotPlayer e) {
Location playerLocation = player.getLocationFull();
Location oPlayerLocation = e.getLocation();
double playerX = playerLocation.getX();
double playerY = playerLocation.getY();
double playerZ = playerLocation.getZ();
double oPlayerX = oPlayerLocation.getX();
double oPlayerY = oPlayerLocation.getY();
double oPlayerZ = oPlayerLocation.getZ();
double x = 0d;
if (playerX < oPlayerX) {
x = 1.0d;
} else if (playerX > oPlayerX) {
x = -1.0d;
}
double y = 0d;
if (playerY < oPlayerY) {
y = 0.5d;
} else if (playerY > oPlayerY) {
y = -0.5d;
}
double z = 0d;
if (playerZ < oPlayerZ) {
z = 1.0d;
} else if (playerZ > oPlayerZ) {
z = -1.0d;
}
return new Vector(x, y, z);
}
public static void handleForcefield(Player player, PlotPlayer plotPlayer, Plot plot) {
if (Flags.FORCEFIELD.isTrue(plot)) {
UUID uuid = plotPlayer.getUUID();
if (plot.isAdded(uuid)) {
Set<PlotPlayer> players = getNearbyPlayers(player, plot);
for (PlotPlayer oPlayer : players) {
if (!Permissions.hasPermission(oPlayer, C.PERMISSION_ADMIN_ENTRY_FORCEFIELD)) {
((BukkitPlayer) oPlayer).player.setVelocity(calculateVelocity(plotPlayer, oPlayer));
}
}
} else {
PlotPlayer oPlayer = hasNearbyPermitted(player, plot);
if (oPlayer == null) {
return;
}
if (!Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_ENTRY_FORCEFIELD)) {
player.setVelocity(calculateVelocity(oPlayer, plotPlayer));
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
package com.plotsquared.bukkit.listeners;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.flag.Flags;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.plotsquared.bukkit.util.BukkitUtil;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockExplodeEvent;
import java.util.Iterator;
public class PlayerEvents183 implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBigBoom(BlockExplodeEvent event) {
Block block = event.getBlock();
Location location = BukkitUtil.getLocation(block.getLocation());
String world = location.getWorld();
if (!PS.get().hasPlotArea(world)) {
return;
}
PlotArea area = location.getPlotArea();
if (area == null) {
Iterator<Block> iterator = event.blockList().iterator();
while (iterator.hasNext()) {
location = BukkitUtil.getLocation(iterator.next().getLocation());
if (location.getPlotArea() != null) {
iterator.remove();
}
}
return;
}
Plot plot = area.getOwnedPlot(location);
if (plot == null || !plot.getFlag(Flags.EXPLOSION).or(false)) {
event.setCancelled(true);
}
Iterator<Block> iterator = event.blockList().iterator();
while (iterator.hasNext()) {
Block b = iterator.next();
if (!plot.equals(area.getOwnedPlot(BukkitUtil.getLocation(b.getLocation())))) {
iterator.remove();
}
}
}
}

View File

@ -1,9 +1,16 @@
package com.plotsquared.bukkit.listeners; package com.plotsquared.bukkit.listeners;
import java.util.HashSet; import com.intellectualcrafters.plot.PS;
import java.util.List; import com.intellectualcrafters.plot.config.C;
import java.util.UUID; import com.intellectualcrafters.plot.flag.Flags;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.Permissions;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.listener.PlotListener;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.entity.ArmorStand; import org.bukkit.entity.ArmorStand;
@ -20,85 +27,78 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import com.intellectualcrafters.plot.PS; import java.util.HashSet;
import com.intellectualcrafters.plot.config.C; import java.util.List;
import com.intellectualcrafters.plot.object.Location; import java.util.UUID;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.Permissions;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.listener.PlotListener;
public class PlayerEvents_1_8 extends PlotListener implements Listener { public class PlayerEvents_1_8 extends PlotListener implements Listener {
@SuppressWarnings("deprecation")
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onInventoryClick(final InventoryClickEvent event) { public void onInventoryClick(InventoryClickEvent event) {
if (!event.isLeftClick() || (event.getAction() != InventoryAction.PLACE_ALL) || event.isShiftClick()) { if (!event.isLeftClick() || (event.getAction() != InventoryAction.PLACE_ALL) || event.isShiftClick()) {
return; return;
} }
final HumanEntity entity = event.getWhoClicked(); HumanEntity entity = event.getWhoClicked();
if (!(entity instanceof Player) || !PS.get().hasPlotArea(entity.getWorld().getName())) { if (!(entity instanceof Player) || !PS.get().hasPlotArea(entity.getWorld().getName())) {
return; return;
} }
final Player player = (Player) entity; Player player = (Player) entity;
final PlayerInventory inv = player.getInventory(); PlayerInventory inv = player.getInventory();
final int slot = inv.getHeldItemSlot(); int slot = inv.getHeldItemSlot();
if ((slot != event.getSlot()) || (slot > 8) || !event.getEventName().equals("InventoryCreativeEvent")) { if ((slot != event.getSlot()) || (slot > 8) || !event.getEventName().equals("InventoryCreativeEvent")) {
return; return;
} }
final ItemStack current = inv.getItemInHand(); ItemStack current = inv.getItemInHand();
final ItemStack newItem = event.getCursor(); ItemStack newItem = event.getCursor();
final ItemMeta newMeta = newItem.getItemMeta(); ItemMeta newMeta = newItem.getItemMeta();
final ItemMeta oldMeta = newItem.getItemMeta(); ItemMeta oldMeta = newItem.getItemMeta();
String newLore = ""; String newLore = "";
if (newMeta != null) { if (newMeta != null) {
final List<String> lore = newMeta.getLore(); List<String> lore = newMeta.getLore();
if (lore != null) { if (lore != null) {
newLore = lore.toString(); newLore = lore.toString();
} }
} }
String oldLore = ""; String oldLore = "";
if (oldMeta != null) { if (oldMeta != null) {
final List<String> lore = oldMeta.getLore(); List<String> lore = oldMeta.getLore();
if (lore != null) { if (lore != null) {
oldLore = lore.toString(); oldLore = lore.toString();
} }
} }
if (!newLore.equals("[(+NBT)]") || (current.equals(newItem) && newLore.equals(oldLore))) { if (!"[(+NBT)]".equals(newLore) || (current.equals(newItem) && newLore.equals(oldLore))) {
return; return;
} }
final HashSet<Byte> blocks = null; HashSet<Byte> blocks = null;
final Block block = player.getTargetBlock(blocks, 7); Block block = player.getTargetBlock(blocks, 7);
final BlockState state = block.getState(); BlockState state = block.getState();
if (state == null) { if (state == null) {
return; return;
} }
if (state.getType() != newItem.getType()) { if (state.getType() != newItem.getType()) {
return; return;
} }
final Location l = BukkitUtil.getLocation(state.getLocation()); Location l = BukkitUtil.getLocation(state.getLocation());
PlotArea area = l.getPlotArea(); PlotArea area = l.getPlotArea();
if (area == null) { if (area == null) {
return; return;
} }
final Plot plot = area.getPlotAbs(l); Plot plot = area.getPlotAbs(l);
final PlotPlayer pp = BukkitUtil.getPlayer(player); PlotPlayer pp = BukkitUtil.getPlayer(player);
boolean cancelled = false; boolean cancelled = false;
if (plot == null) { if (plot == null) {
if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) { if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) {
MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.road"); MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.road");
cancelled = true; cancelled = true;
} }
} else { } else if (!plot.hasOwner()) {
if (!plot.hasOwner()) {
if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) { if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) {
MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.unowned"); MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.unowned");
cancelled = true; cancelled = true;
} }
} else { } else {
final UUID uuid = pp.getUUID(); UUID uuid = pp.getUUID();
if (!plot.isAdded(uuid)) { if (!plot.isAdded(uuid)) {
if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) { if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) {
MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.other"); MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.other");
@ -106,44 +106,45 @@ public class PlayerEvents_1_8 extends PlotListener implements Listener {
} }
} }
} }
}
if (cancelled) { if (cancelled) {
if ((current.getTypeId() == newItem.getTypeId()) && (current.getDurability() == newItem.getDurability())) { if ((current.getType() == newItem.getType()) && (current.getDurability() == newItem.getDurability())) {
event.setCursor(new ItemStack(newItem.getTypeId(), newItem.getAmount(), newItem.getDurability())); event.setCursor(new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability()));
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
event.setCursor(new ItemStack(newItem.getTypeId(), newItem.getAmount(), newItem.getDurability())); event.setCursor(new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability()));
} }
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onInteract(final PlayerInteractAtEntityEvent e) { public void onInteract(PlayerInteractAtEntityEvent e) {
final Entity entity = e.getRightClicked(); Entity entity = e.getRightClicked();
if (!(entity instanceof ArmorStand)) { if (!(entity instanceof ArmorStand)) {
return; return;
} }
final Location l = BukkitUtil.getLocation(e.getRightClicked().getLocation()); Location l = BukkitUtil.getLocation(e.getRightClicked().getLocation());
final PlotArea area = l.getPlotArea(); PlotArea area = l.getPlotArea();
if (area == null) { if (area == null) {
return; return;
} }
final Plot plot = area.getPlotAbs(l); Plot plot = area.getPlotAbs(l);
final PlotPlayer pp = BukkitUtil.getPlayer(e.getPlayer()); PlotPlayer pp = BukkitUtil.getPlayer(e.getPlayer());
if (plot == null) { if (plot == null) {
if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) { if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) {
MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.road"); MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.road");
e.setCancelled(true); e.setCancelled(true);
} }
} else { } else if (!plot.hasOwner()) {
if (!plot.hasOwner()) {
if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) { if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) {
MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.unowned"); MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.unowned");
e.setCancelled(true); e.setCancelled(true);
} }
} else { } else {
final UUID uuid = pp.getUUID(); UUID uuid = pp.getUUID();
if (!plot.isAdded(uuid)) { if (!plot.isAdded(uuid)) {
if (Flags.MISC_INTERACT.isTrue(plot)) {
return;
}
if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) { if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) {
MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.other"); MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.other");
e.setCancelled(true); e.setCancelled(true);
@ -152,4 +153,3 @@ public class PlayerEvents_1_8 extends PlotListener implements Listener {
} }
} }
} }
}

View File

@ -0,0 +1,31 @@
package com.plotsquared.bukkit.listeners;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.object.Location;
import com.plotsquared.bukkit.util.BukkitUtil;
import org.bukkit.entity.LingeringPotion;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.LingeringPotionSplashEvent;
public class PlayerEvents_1_9 implements Listener {
private final PlayerEvents parent;
public PlayerEvents_1_9(PlayerEvents parent) {
this.parent = parent;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPotionSplash(LingeringPotionSplashEvent event) {
LingeringPotion entity = event.getEntity();
Location l = BukkitUtil.getLocation(entity);
if (!PS.get().hasPlotArea(l.getWorld())) {
return;
}
if (!parent.onProjectileHit(event)) {
event.setCancelled(true);
}
}
}

View File

@ -0,0 +1,198 @@
package com.plotsquared.bukkit.listeners;
import com.google.common.base.Optional;
import com.intellectualcrafters.plot.flag.Flags;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.plotsquared.bukkit.events.PlayerEnterPlotEvent;
import com.plotsquared.bukkit.events.PlayerLeavePlotEvent;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.listener.PlotListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.block.Block;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.java.JavaPlugin;
public class PlotPlusListener extends PlotListener implements Listener {
private static final HashMap<String, Interval> feedRunnable = new HashMap<>();
private static final HashMap<String, Interval> healRunnable = new HashMap<>();
public static void startRunnable(JavaPlugin plugin) {
plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
@Override
public void run() {
if (!healRunnable.isEmpty()) {
for (Iterator<Entry<String, Interval>> iterator = healRunnable.entrySet().iterator(); iterator.hasNext(); ) {
Entry<String, Interval> entry = iterator.next();
Interval value = entry.getValue();
++value.count;
if (value.count == value.interval) {
value.count = 0;
Player player = Bukkit.getPlayer(entry.getKey());
if (player == null) {
iterator.remove();
continue;
}
double level = player.getHealth();
if (level != value.max) {
player.setHealth(Math.min(level + value.amount, value.max));
}
}
}
}
if (!feedRunnable.isEmpty()) {
for (Iterator<Entry<String, Interval>> iterator = feedRunnable.entrySet().iterator(); iterator.hasNext(); ) {
Entry<String, Interval> entry = iterator.next();
Interval value = entry.getValue();
++value.count;
if (value.count == value.interval) {
value.count = 0;
Player player = Bukkit.getPlayer(entry.getKey());
if (player == null) {
iterator.remove();
continue;
}
int level = player.getFoodLevel();
if (level != value.max) {
player.setFoodLevel(Math.min(level + value.amount, value.max));
}
}
}
}
}
}, 0L, 20L);
}
@EventHandler(priority = EventPriority.HIGH)
public void onInteract(BlockDamageEvent event) {
Player player = event.getPlayer();
if (player.getGameMode() != GameMode.SURVIVAL) {
return;
}
Plot plot = BukkitUtil.getLocation(player).getOwnedPlot();
if (plot == null) {
return;
}
if (Flags.INSTABREAK.isTrue(plot)) {
Block block = event.getBlock();
BlockBreakEvent call = new BlockBreakEvent(block, player);
Bukkit.getServer().getPluginManager().callEvent(call);
if (!call.isCancelled()) {
event.getBlock().breakNaturally();
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onDamage(EntityDamageEvent event) {
if (event.getEntityType() != EntityType.PLAYER) {
return;
}
Player player = (Player) event.getEntity();
Plot plot = BukkitUtil.getLocation(player).getOwnedPlot();
if (plot == null) {
return;
}
if (Flags.INVINCIBLE.isTrue(plot)) {
event.setCancelled(true);
}
}
@EventHandler
public void onItemPickup(PlayerPickupItemEvent event) {
Player player = event.getPlayer();
PlotPlayer pp = BukkitUtil.getPlayer(player);
Plot plot = BukkitUtil.getLocation(player).getOwnedPlot();
if (plot == null) {
return;
}
UUID uuid = pp.getUUID();
if (plot.isAdded(uuid) && Flags.DROP_PROTECTION.isTrue(plot)) {
event.setCancelled(true);
}
}
@EventHandler
public void onItemDrop(PlayerDropItemEvent event) {
Player player = event.getPlayer();
PlotPlayer pp = BukkitUtil.getPlayer(player);
Plot plot = BukkitUtil.getLocation(player).getOwnedPlot();
if (plot == null) {
return;
}
UUID uuid = pp.getUUID();
if (!plot.isAdded(uuid)) {
if (Flags.ITEM_DROP.isFalse(plot)) {
event.setCancelled(true);
}
}
}
@EventHandler
public void onPlotEnter(PlayerEnterPlotEvent event) {
Player player = event.getPlayer();
Plot plot = event.getPlot();
Optional<Integer[]> feed = plot.getFlag(Flags.FEED);
if (feed.isPresent()) {
Integer[] value = feed.get();
feedRunnable.put(player.getName(), new Interval(value[0], value[1], 20));
}
Optional<Integer[]> heal = plot.getFlag(Flags.HEAL);
if (heal.isPresent()) {
Integer[] value = heal.get();
healRunnable.put(player.getName(), new Interval(value[0], value[1], 20));
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
String name = player.getName();
feedRunnable.remove(name);
healRunnable.remove(name);
}
@EventHandler
public void onPlotLeave(PlayerLeavePlotEvent event) {
Player leaver = event.getPlayer();
Plot plot = event.getPlot();
if (!plot.hasOwner()) {
return;
}
BukkitUtil.getPlayer(leaver);
String name = leaver.getName();
feedRunnable.remove(name);
healRunnable.remove(name);
}
private static class Interval {
final int interval;
final int amount;
final int max;
public int count = 0;
Interval(int interval, int amount, int max) {
this.interval = interval;
this.amount = amount;
this.max = max;
}
}
}

View File

@ -1,5 +1,10 @@
package com.plotsquared.bukkit.listeners; package com.plotsquared.bukkit.listeners;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.generator.GeneratorWrapper;
import com.intellectualcrafters.plot.object.worlds.PlotAreaManager;
import com.intellectualcrafters.plot.object.worlds.SinglePlotAreaManager;
import com.plotsquared.bukkit.generator.BukkitPlotGenerator;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@ -7,34 +12,25 @@ import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent; import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.generator.GeneratorWrapper;
import com.plotsquared.bukkit.generator.BukkitPlotGenerator;
public class WorldEvents implements Listener { public class WorldEvents implements Listener {
public static String lastWorld = null;
public static String getName(final World world) {
if ((lastWorld != null) && !lastWorld.equals("CheckingPlotSquaredGenerator")) {
return lastWorld;
} else {
return world.getName();
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public static void onWorldInit(final WorldInitEvent event) { public void onWorldInit(WorldInitEvent event) {
final World world = event.getWorld(); World world = event.getWorld();
final String name = getName(world); String name = world.getName();
final ChunkGenerator gen = world.getGenerator(); PlotAreaManager manager = PS.get().getPlotAreaManager();
if (manager instanceof SinglePlotAreaManager) {
SinglePlotAreaManager single = (SinglePlotAreaManager) manager;
if (single.isWorld(name)) {
world.setKeepSpawnInMemory(false);
return;
}
}
ChunkGenerator gen = world.getGenerator();
if (gen instanceof GeneratorWrapper) { if (gen instanceof GeneratorWrapper) {
PS.get().loadWorld(name, (GeneratorWrapper<?>) gen); PS.get().loadWorld(name, (GeneratorWrapper<?>) gen);
} else { } else {
if (PS.get().config.contains("worlds." + name)) {
PS.get().loadWorld(name, new BukkitPlotGenerator(name, gen)); PS.get().loadWorld(name, new BukkitPlotGenerator(name, gen));
} }
} }
lastWorld = null;
}
} }

View File

@ -1,9 +1,8 @@
package com.plotsquared.bukkit.object; package com.plotsquared.bukkit.object;
import org.bukkit.block.Block;
import com.intellectualcrafters.plot.object.LazyBlock; import com.intellectualcrafters.plot.object.LazyBlock;
import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.object.PlotBlock;
import org.bukkit.block.Block;
public class BukkitLazyBlock extends LazyBlock { public class BukkitLazyBlock extends LazyBlock {
@ -11,30 +10,30 @@ public class BukkitLazyBlock extends LazyBlock {
private Block block; private Block block;
private PlotBlock pb; private PlotBlock pb;
public BukkitLazyBlock(final int id, final Block block) { public BukkitLazyBlock(int id, Block block) {
this.id = id; this.id = id;
this.block = block; this.block = block;
} }
public BukkitLazyBlock(final PlotBlock pb) { public BukkitLazyBlock(PlotBlock pb) {
id = pb.id; this.id = pb.id;
this.pb = pb; this.pb = pb;
} }
public BukkitLazyBlock(final Block block) { public BukkitLazyBlock(Block block) {
this.block = block; this.block = block;
} }
@Override @Override
public PlotBlock getPlotBlock() { public PlotBlock getPlotBlock() {
if (pb != null) { if (this.pb != null) {
return pb; return this.pb;
} }
if (id == 0) { if (this.id == 0) {
id = block.getTypeId(); this.id = this.block.getTypeId();
} }
byte data; byte data;
switch (id) { switch (this.id) {
case 0: case 0:
case 2: case 2:
case 4: case 4:
@ -120,20 +119,20 @@ public class BukkitLazyBlock extends LazyBlock {
data = 0; data = 0;
break; break;
default: default:
data = block.getData(); data = this.block.getData();
break; break;
} }
pb = new PlotBlock((short) id, data); this.pb = PlotBlock.get((short) this.id, data);
return pb; return this.pb;
} }
@Override @Override
public int getId() { public int getId() {
if (id == 0) { if (this.id == 0) {
id = block.getTypeId(); this.id = this.block.getTypeId();
} }
return id; return this.id;
} }
} }

View File

@ -1,40 +1,41 @@
package com.plotsquared.bukkit.object; package com.plotsquared.bukkit.object;
import java.util.UUID; import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import com.intellectualcrafters.plot.object.OfflinePlotPlayer; import java.util.UUID;
public class BukkitOfflinePlayer implements OfflinePlotPlayer { public class BukkitOfflinePlayer implements OfflinePlotPlayer {
public final OfflinePlayer player; public final OfflinePlayer player;
/** /**
* Please do not use this method. Instead use BukkitUtil.getPlayer(Player), as it caches player objects. * Please do not use this method. Instead use BukkitUtil.getPlayer(Player),
* as it caches player objects.
*
* @param player * @param player
*/ */
public BukkitOfflinePlayer(final OfflinePlayer player) { public BukkitOfflinePlayer(OfflinePlayer player) {
this.player = player; this.player = player;
} }
@Override @Override
public UUID getUUID() { public UUID getUUID() {
return player.getUniqueId(); return this.player.getUniqueId();
} }
@Override @Override
public long getLastPlayed() { public long getLastPlayed() {
return player.getLastPlayed(); return this.player.getLastPlayed();
} }
@Override @Override
public boolean isOnline() { public boolean isOnline() {
return player.isOnline(); return this.player.isOnline();
} }
@Override @Override
public String getName() { public String getName() {
return player.getName(); return this.player.getName();
} }
} }

View File

@ -0,0 +1,249 @@
package com.plotsquared.bukkit.object;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.EconHandler;
import com.intellectualcrafters.plot.util.PlotGameMode;
import com.intellectualcrafters.plot.util.PlotWeather;
import com.intellectualcrafters.plot.util.StringMan;
import com.intellectualcrafters.plot.util.UUIDHandler;
import com.plotsquared.bukkit.util.BukkitUtil;
import org.bukkit.Effect;
import org.bukkit.GameMode;
import org.bukkit.WeatherType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventException;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.UUID;
import org.bukkit.plugin.RegisteredListener;
public class BukkitPlayer extends PlotPlayer {
public final Player player;
public boolean offline;
private UUID uuid;
private String name;
/**
* <p>Please do not use this method. Instead use
* BukkitUtil.getPlayer(Player), as it caches player objects.</p>
* @param player
*/
public BukkitPlayer(Player player) {
this.player = player;
super.populatePersistentMetaMap();
}
public BukkitPlayer(Player player, boolean offline) {
this.player = player;
this.offline = offline;
super.populatePersistentMetaMap();
}
@Override
public Location getLocation() {
Location location = super.getLocation();
return location == null ? BukkitUtil.getLocation(this.player) : location;
}
@Override
public UUID getUUID() {
if (this.uuid == null) {
this.uuid = UUIDHandler.getUUID(this);
}
return this.uuid;
}
@Override public long getLastPlayed() {
return this.player.getLastPlayed();
}
@Override
public boolean canTeleport(Location loc) {
org.bukkit.Location to = BukkitUtil.getLocation(loc);
org.bukkit.Location from = player.getLocation();
PlayerTeleportEvent event = new PlayerTeleportEvent(player, from, to);
RegisteredListener[] listeners = event.getHandlers().getRegisteredListeners();
for (RegisteredListener listener : listeners) {
if (listener.getPlugin().getName().equals(PS.imp().getPluginName())) {
continue;
}
try {
listener.callEvent(event);
} catch (EventException e) {
e.printStackTrace();
}
}
if (event.isCancelled() || !event.getTo().equals(to)) {
return false;
}
event = new PlayerTeleportEvent(player, to, from);
for (RegisteredListener listener : listeners) {
if (listener.getPlugin().getName().equals(PS.imp().getPluginName())) {
continue;
}
try {
listener.callEvent(event);
} catch (EventException e) {
e.printStackTrace();
}
}
return true;
}
@Override
public boolean hasPermission(String permission) {
if (this.offline && EconHandler.manager != null) {
return EconHandler.manager.hasPermission(getName(), permission);
}
return this.player.hasPermission(permission);
}
@Override
public boolean isPermissionSet(String permission) {
return this.player.isPermissionSet(permission);
}
@Override
public void sendMessage(String message) {
if (!StringMan.isEqual(this.<String>getMeta("lastMessage"), message) || (System.currentTimeMillis() - this.<Long>getMeta("lastMessageTime") > 5000)) {
setMeta("lastMessage", message);
setMeta("lastMessageTime", System.currentTimeMillis());
this.player.sendMessage(message);
}
}
@Override
public void teleport(Location location) {
if (Math.abs(location.getX()) >= 30000000 || Math.abs(location.getZ()) >= 30000000) {
return;
}
this.player.teleport(
new org.bukkit.Location(BukkitUtil.getWorld(location.getWorld()), location.getX() + 0.5, location.getY(), location.getZ() + 0.5,
location.getYaw(), location.getPitch()), TeleportCause.COMMAND);
}
@Override
public String getName() {
if (this.name == null) {
this.name = this.player.getName();
}
return this.name;
}
@Override
public boolean isOnline() {
return !this.offline && this.player.isOnline();
}
@Override
public void setCompassTarget(Location location) {
this.player.setCompassTarget(
new org.bukkit.Location(BukkitUtil.getWorld(location.getWorld()), location.getX(), location.getY(), location.getZ()));
}
@Override
public Location getLocationFull() {
return BukkitUtil.getLocationFull(this.player);
}
@Override
public void setWeather(PlotWeather weather) {
switch (weather) {
case CLEAR:
this.player.setPlayerWeather(WeatherType.CLEAR);
break;
case RAIN:
this.player.setPlayerWeather(WeatherType.DOWNFALL);
break;
case RESET:
this.player.resetPlayerWeather();
break;
default:
this.player.resetPlayerWeather();
break;
}
}
@Override
public PlotGameMode getGameMode() {
switch (this.player.getGameMode()) {
case ADVENTURE:
return PlotGameMode.ADVENTURE;
case CREATIVE:
return PlotGameMode.CREATIVE;
case SPECTATOR:
return PlotGameMode.SPECTATOR;
case SURVIVAL:
return PlotGameMode.SURVIVAL;
default:
return PlotGameMode.NOT_SET;
}
}
@Override
public void setGameMode(PlotGameMode gameMode) {
switch (gameMode) {
case ADVENTURE:
this.player.setGameMode(GameMode.ADVENTURE);
break;
case CREATIVE:
this.player.setGameMode(GameMode.CREATIVE);
break;
case SPECTATOR:
this.player.setGameMode(GameMode.SPECTATOR);
break;
case SURVIVAL:
this.player.setGameMode(GameMode.SURVIVAL);
break;
default:
this.player.setGameMode(GameMode.SURVIVAL);
break;
}
}
@Override
public void setTime(long time) {
if (time != Long.MAX_VALUE) {
this.player.setPlayerTime(time, false);
} else {
this.player.resetPlayerTime();
}
}
@Override
public void setFlight(boolean fly) {
this.player.setAllowFlight(fly);
}
@Override
public boolean getFlight() {
return player.getAllowFlight();
}
@Override
public void playMusic(Location location, int id) {
//noinspection deprecation
this.player.playEffect(BukkitUtil.getLocation(location), Effect.RECORD_PLAY, id);
}
@Override
public void kick(String message) {
this.player.kickPlayer(message);
}
@Override public void stopSpectating() {
if (getGameMode() == PlotGameMode.SPECTATOR) {
this.player.setSpectatorTarget(null);
}
}
@Override
public boolean isBanned() {
return this.player.isBanned();
}
}

View File

@ -0,0 +1,8 @@
package com.plotsquared.bukkit.object.entity;
class AgeableStats {
int age;
boolean locked;
boolean adult;
}

View File

@ -0,0 +1,15 @@
package com.plotsquared.bukkit.object.entity;
class ArmorStandStats {
final float[] head = new float[3];
final float[] body = new float[3];
final float[] leftLeg = new float[3];
final float[] rightLeg = new float[3];
final float[] leftArm = new float[3];
final float[] rightArm = new float[3];
boolean arms;
boolean noPlate;
boolean invisible;
boolean small;
}

View File

@ -0,0 +1,13 @@
package com.plotsquared.bukkit.object.entity;
class EntityBaseStats {
EntityWrapper passenger;
float fall;
short fire;
int age;
double vZ;
double vY;
double vX;
}

View File

@ -0,0 +1,737 @@
package com.plotsquared.bukkit.object.entity;
import com.intellectualcrafters.plot.PS;
import com.plotsquared.bukkit.util.BukkitVersion;
import org.bukkit.Art;
import org.bukkit.DyeColor;
import org.bukkit.Location;
import org.bukkit.Rotation;
import org.bukkit.TreeSpecies;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Bat;
import org.bukkit.entity.Boat;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Guardian;
import org.bukkit.entity.Horse;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.Item;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Rabbit;
import org.bukkit.entity.Rabbit.Type;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Skeleton;
import org.bukkit.entity.Skeleton.SkeletonType;
import org.bukkit.entity.Slime;
import org.bukkit.entity.Tameable;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.EulerAngle;
import org.bukkit.util.Vector;
public class EntityWrapper {
private final EntityType type;
private final float yaw;
private final float pitch;
private final short depth;
private final int hash;
private final EntityBaseStats base = new EntityBaseStats();
public double x;
public double y;
public double z;
public ItemStack[] inventory;
// Extended
private ItemStack stack;
private byte dataByte;
private byte dataByte2;
private String dataString;
private LivingEntityStats lived;
private AgeableStats aged;
private TameableStats tamed;
private ArmorStandStats stand;
private HorseStats horse;
private boolean noGravity;
public EntityWrapper(Entity entity, short depth) {
this.hash = entity.getEntityId();
this.depth = depth;
Location location = entity.getLocation();
this.yaw = location.getYaw();
this.pitch = location.getPitch();
this.x = location.getX();
this.y = location.getY();
this.z = location.getZ();
this.type = entity.getType();
if (depth == 0) {
return;
}
Entity passenger = entity.getPassenger();
if (passenger != null) {
this.base.passenger = new EntityWrapper(passenger, depth);
}
this.base.fall = entity.getFallDistance();
this.base.fire = (short) entity.getFireTicks();
this.base.age = entity.getTicksLived();
Vector velocity = entity.getVelocity();
this.base.vX = velocity.getX();
this.base.vY = velocity.getY();
this.base.vZ = velocity.getZ();
if (depth == 1) {
return;
}
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_10_0) || entity instanceof ArmorStand) {
if (!entity.hasGravity()) {
this.noGravity = true;
}
}
switch (entity.getType()) {
case ARROW:
case BOAT:
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_0)) {
Boat boat = (Boat) entity;
this.dataByte = getOrdinal(TreeSpecies.values(), boat.getWoodType());
}
case COMPLEX_PART:
case EGG:
case ENDER_CRYSTAL:
case ENDER_PEARL:
case ENDER_SIGNAL:
case EXPERIENCE_ORB:
case FALLING_BLOCK:
case FIREBALL:
case FIREWORK:
case FISHING_HOOK:
case LEASH_HITCH:
case LIGHTNING:
case MINECART:
case MINECART_COMMAND:
case MINECART_MOB_SPAWNER:
case MINECART_TNT:
case PLAYER:
case PRIMED_TNT:
case SLIME:
case SMALL_FIREBALL:
case SNOWBALL:
case MINECART_FURNACE:
case SPLASH_POTION:
case THROWN_EXP_BOTTLE:
case WEATHER:
case WITHER_SKULL:
case UNKNOWN:
case TIPPED_ARROW:
case SPECTRAL_ARROW:
case SHULKER_BULLET:
case DRAGON_FIREBALL:
case LINGERING_POTION:
case AREA_EFFECT_CLOUD:
// Do this stuff later
return;
default:
PS.debug("&cCOULD NOT IDENTIFY ENTITY: " + entity.getType());
return;
// MISC //
case DROPPED_ITEM:
Item item = (Item) entity;
this.stack = item.getItemStack();
return;
case ITEM_FRAME:
this.x = Math.floor(this.x);
this.y = Math.floor(this.y);
this.z = Math.floor(this.z);
ItemFrame itemFrame = (ItemFrame) entity;
this.dataByte = getOrdinal(Rotation.values(), itemFrame.getRotation());
this.stack = itemFrame.getItem().clone();
return;
case PAINTING:
this.x = Math.floor(this.x);
this.y = Math.floor(this.y);
this.z = Math.floor(this.z);
Painting painting = (Painting) entity;
Art art = painting.getArt();
this.dataByte = getOrdinal(BlockFace.values(), painting.getFacing());
int h = art.getBlockHeight();
if (h % 2 == 0) {
this.y -= 1;
}
this.dataString = art.name();
return;
// END MISC //
// INVENTORY HOLDER //
case MINECART_CHEST:
case MINECART_HOPPER:
storeInventory((InventoryHolder) entity);
return;
// START LIVING ENTITY //
// START AGEABLE //
// START TAMEABLE //
case HORSE:
Horse horse = (Horse) entity;
this.horse = new HorseStats();
this.horse.jump = horse.getJumpStrength();
this.horse.chest = horse.isCarryingChest();
this.horse.variant = horse.getVariant();
this.horse.style = horse.getStyle();
this.horse.color = horse.getColor();
storeTameable(horse);
storeAgeable(horse);
storeLiving(horse);
storeInventory(horse);
return;
// END INVENTORY HOLDER //
case WOLF:
case OCELOT:
storeTameable((Tameable) entity);
storeAgeable((Ageable) entity);
storeLiving((LivingEntity) entity);
return;
// END TAMEABLE //
case SHEEP:
Sheep sheep = (Sheep) entity;
this.dataByte = (byte) (sheep.isSheared() ? 1 : 0);
this.dataByte2 = sheep.getColor().getDyeData();
storeAgeable(sheep);
storeLiving(sheep);
return;
case VILLAGER:
case CHICKEN:
case COW:
case MUSHROOM_COW:
case PIG:
case POLAR_BEAR:
storeAgeable((Ageable) entity);
storeLiving((LivingEntity) entity);
return;
case RABBIT:
this.dataByte = getOrdinal(Type.values(), ((Rabbit) entity).getRabbitType());
storeAgeable((Ageable) entity);
storeLiving((LivingEntity) entity);
return;
// END AGEABLE //
case GUARDIAN:
this.dataByte = (byte) (((Guardian) entity).isElder() ? 1 : 0);
storeLiving((LivingEntity) entity);
return;
case SKELETON:
this.dataByte = getOrdinal(SkeletonType.values(),((Skeleton)entity).getSkeletonType());
storeLiving((LivingEntity) entity);
return;
case ARMOR_STAND:
ArmorStand stand = (ArmorStand) entity;
this.inventory = new ItemStack[]{stand.getItemInHand().clone(), stand.getHelmet().clone(), stand.getChestplate().clone(),
stand.getLeggings().clone(), stand.getBoots().clone()};
storeLiving(stand);
this.stand = new ArmorStandStats();
EulerAngle head = stand.getHeadPose();
this.stand.head[0] = (float) head.getX();
this.stand.head[1] = (float) head.getY();
this.stand.head[2] = (float) head.getZ();
EulerAngle body = stand.getBodyPose();
this.stand.body[0] = (float) body.getX();
this.stand.body[1] = (float) body.getY();
this.stand.body[2] = (float) body.getZ();
EulerAngle leftLeg = stand.getLeftLegPose();
this.stand.leftLeg[0] = (float) leftLeg.getX();
this.stand.leftLeg[1] = (float) leftLeg.getY();
this.stand.leftLeg[2] = (float) leftLeg.getZ();
EulerAngle rightLeg = stand.getRightLegPose();
this.stand.rightLeg[0] = (float) rightLeg.getX();
this.stand.rightLeg[1] = (float) rightLeg.getY();
this.stand.rightLeg[2] = (float) rightLeg.getZ();
EulerAngle leftArm = stand.getLeftArmPose();
this.stand.leftArm[0] = (float) leftArm.getX();
this.stand.leftArm[1] = (float) leftArm.getY();
this.stand.leftArm[2] = (float) leftArm.getZ();
EulerAngle rightArm = stand.getRightArmPose();
this.stand.rightArm[0] = (float) rightArm.getX();
this.stand.rightArm[1] = (float) rightArm.getY();
this.stand.rightArm[2] = (float) rightArm.getZ();
if (stand.hasArms()) {
this.stand.arms = true;
}
if (!stand.hasBasePlate()) {
this.stand.noPlate = true;
}
if (!stand.isVisible()) {
this.stand.invisible = true;
}
if (stand.isSmall()) {
this.stand.small = true;
}
return;
case ENDERMITE:
return;
case BAT:
if (((Bat) entity).isAwake()) {
this.dataByte = (byte) 1;
} else {
this.dataByte = (byte) 0;
}
return;
case ENDER_DRAGON:
EnderDragon entity1 = (EnderDragon) entity;
this.dataByte = (byte) entity1.getPhase().ordinal();
return;
case GHAST:
case MAGMA_CUBE:
case SQUID:
case PIG_ZOMBIE:
case ZOMBIE:
case WITHER:
case WITCH:
case SPIDER:
case CAVE_SPIDER:
case SILVERFISH:
case GIANT:
case ENDERMAN:
case CREEPER:
case BLAZE:
case SHULKER:
case SNOWMAN:
storeLiving((LivingEntity) entity);
return;
case IRON_GOLEM:
if (((IronGolem) entity).isPlayerCreated()) {
this.dataByte = (byte) 1;
} else {
this.dataByte = (byte) 0;
}
storeLiving((LivingEntity) entity);
// END LIVING //
}
}
@Override
public boolean equals(Object obj) {
return this.hash == obj.hashCode();
}
@Override
public int hashCode() {
return this.hash;
}
public void storeInventory(InventoryHolder held) {
this.inventory = held.getInventory().getContents().clone();
}
void restoreLiving(LivingEntity entity) {
entity.setCanPickupItems(this.lived.loot);
if (this.lived.name != null) {
entity.setCustomName(this.lived.name);
entity.setCustomNameVisible(this.lived.visible);
}
if (this.lived.potions != null && !this.lived.potions.isEmpty()) {
entity.addPotionEffects(this.lived.potions);
}
entity.setRemainingAir(this.lived.air);
entity.setRemoveWhenFarAway(this.lived.persistent);
if (this.lived.equipped) {
this.restoreEquipment(entity);
}
if (this.lived.leashed) {
// TODO leashes
// World world = entity.getWorld();
// Entity leash = world.spawnEntity(new Location(world, Math.floor(x) + lived.leashX, Math.floor(y) + lived.leashY, Math
// .floor(z) + lived.leashZ), EntityType.LEASH_HITCH);
// entity.setLeashHolder(leash);
}
}
void restoreEquipment(LivingEntity entity) {
EntityEquipment equipment = entity.getEquipment();
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_0)) {
equipment.setItemInMainHand(this.lived.mainHand);
equipment.setItemInOffHand(this.lived.offHand);
} else {
equipment.setItemInHand(this.lived.mainHand);
}
equipment.setHelmet(this.lived.helmet);
equipment.setChestplate(this.lived.chestplate);
equipment.setLeggings(this.lived.leggings);
equipment.setBoots(this.lived.boots);
}
private void restoreInventory(InventoryHolder entity) {
try {
entity.getInventory().setContents(this.inventory);
} catch (IllegalArgumentException e) {
PS.debug("&c[WARN] Failed to restore inventory.\n Reason: " + e.getMessage());
}
}
public void storeLiving(LivingEntity lived) {
this.lived = new LivingEntityStats();
this.lived.potions = lived.getActivePotionEffects();
this.lived.loot = lived.getCanPickupItems();
this.lived.name = lived.getCustomName();
this.lived.visible = lived.isCustomNameVisible();
this.lived.health = (float) lived.getHealth();
this.lived.air = (short) lived.getRemainingAir();
this.lived.persistent = lived.getRemoveWhenFarAway();
this.lived.leashed = lived.isLeashed();
if (this.lived.leashed) {
Location location = lived.getLeashHolder().getLocation();
this.lived.leashX = (short) (this.x - location.getBlockX());
this.lived.leashY = (short) (this.y - location.getBlockY());
this.lived.leashZ = (short) (this.z - location.getBlockZ());
}
EntityEquipment equipment = lived.getEquipment();
this.lived.equipped = equipment != null;
if (this.lived.equipped) {
storeEquipment(equipment);
}
}
void storeEquipment(EntityEquipment equipment) {
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_0)) {
this.lived.mainHand = equipment.getItemInMainHand().clone();
this.lived.offHand = equipment.getItemInOffHand().clone();
} else {
this.lived.mainHand = equipment.getItemInHand().clone();
this.lived.offHand = null;
}
this.lived.boots = equipment.getBoots().clone();
this.lived.leggings = equipment.getLeggings().clone();
this.lived.chestplate = equipment.getChestplate().clone();
this.lived.helmet = equipment.getHelmet().clone();
}
private void restoreTameable(Tameable entity) {
if (this.tamed.tamed) {
if (this.tamed.owner != null) {
entity.setTamed(true);
entity.setOwner(this.tamed.owner);
}
}
}
private void restoreAgeable(Ageable entity) {
if (!this.aged.adult) {
entity.setBaby();
}
entity.setAgeLock(this.aged.locked);
if (this.aged.age > 0) {
entity.setAge(this.aged.age);
}
}
public void storeAgeable(Ageable aged) {
this.aged = new AgeableStats();
this.aged.age = aged.getAge();
this.aged.locked = aged.getAgeLock();
this.aged.adult = aged.isAdult();
}
public void storeTameable(Tameable tamed) {
this.tamed = new TameableStats();
this.tamed.owner = tamed.getOwner();
this.tamed.tamed = tamed.isTamed();
}
public Entity spawn(World world, int xOffset, int zOffset) {
Location location = new Location(world, this.x + xOffset, this.y, this.z + zOffset);
location.setYaw(this.yaw);
location.setPitch(this.pitch);
if (!this.type.isSpawnable()) {
return null;
}
Entity entity;
switch (this.type) {
case DROPPED_ITEM:
return world.dropItem(location, this.stack);
case PLAYER:
case LEASH_HITCH:
return null;
case ITEM_FRAME:
entity = world.spawn(location, ItemFrame.class);
break;
case PAINTING:
entity = world.spawn(location, Painting.class);
break;
default:
entity = world.spawnEntity(location, this.type);
break;
}
if (this.depth == 0) {
return entity;
}
if (this.base.passenger != null) {
try {
entity.setPassenger(this.base.passenger.spawn(world, xOffset, zOffset));
} catch (Exception ignored) { }
}
if (this.base.fall != 0) {
entity.setFallDistance(this.base.fall);
}
if (this.base.fire != 0) {
entity.setFireTicks(this.base.fire);
}
if (this.base.age != 0) {
entity.setTicksLived(this.base.age);
}
entity.setVelocity(new Vector(this.base.vX, this.base.vY, this.base.vZ));
if (this.depth == 1) {
return entity;
}
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_10_0) || entity instanceof ArmorStand) {
if (this.noGravity) {
entity.setGravity(false);
}
}
switch (entity.getType()) {
case ARROW:
case BOAT:
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_0)) {
Boat boat = (Boat) entity;
boat.setWoodType(TreeSpecies.values()[dataByte]);
}
case COMPLEX_PART:
case EGG:
case ENDER_CRYSTAL:
case ENDER_PEARL:
case ENDER_SIGNAL:
case DROPPED_ITEM:
case EXPERIENCE_ORB:
case FALLING_BLOCK:
case FIREBALL:
case FIREWORK:
case FISHING_HOOK:
case LEASH_HITCH:
case LIGHTNING:
case MINECART:
case MINECART_COMMAND:
case MINECART_MOB_SPAWNER:
case MINECART_TNT:
case PLAYER:
case PRIMED_TNT:
return entity;
case SLIME:
((Slime) entity).setSize(this.dataByte);
return entity;
case SMALL_FIREBALL:
case SNOWBALL:
case SPLASH_POTION:
case THROWN_EXP_BOTTLE:
case WEATHER:
case TIPPED_ARROW:
case SPECTRAL_ARROW:
case SHULKER_BULLET:
case LINGERING_POTION:
case AREA_EFFECT_CLOUD:
case DRAGON_FIREBALL:
case WITHER_SKULL:
case MINECART_FURNACE:
case UNKNOWN:
// Do this stuff later
return entity;
default:
PS.debug("&cCOULD NOT IDENTIFY ENTITY: " + entity.getType());
return entity;
// MISC //
case ITEM_FRAME:
ItemFrame itemframe = (ItemFrame) entity;
itemframe.setRotation(Rotation.values()[this.dataByte]);
itemframe.setItem(this.stack);
return entity;
case PAINTING:
Painting painting = (Painting) entity;
painting.setFacingDirection(BlockFace.values()[this.dataByte], true);
painting.setArt(Art.getByName(this.dataString), true);
return entity;
// END MISC //
// INVENTORY HOLDER //
case MINECART_CHEST:
case MINECART_HOPPER:
restoreInventory((InventoryHolder) entity);
return entity;
// START LIVING ENTITY //
// START AGEABLE //
// START TAMEABLE //
case HORSE:
Horse horse = (Horse) entity;
horse.setJumpStrength(this.horse.jump);
horse.setCarryingChest(this.horse.chest);
horse.setVariant(this.horse.variant);
horse.setStyle(this.horse.style);
horse.setColor(this.horse.color);
restoreTameable(horse);
restoreAgeable(horse);
restoreLiving(horse);
restoreInventory(horse);
return entity;
// END INVENTORY HOLDER //
case WOLF:
case OCELOT:
restoreTameable((Tameable) entity);
restoreAgeable((Ageable) entity);
restoreLiving((LivingEntity) entity);
return entity;
// END AGEABLE //
case SHEEP:
Sheep sheep = (Sheep) entity;
if (this.dataByte == 1) {
sheep.setSheared(true);
}
if (this.dataByte2 != 0) {
sheep.setColor(DyeColor.getByDyeData(this.dataByte2));
}
restoreAgeable(sheep);
restoreLiving(sheep);
return sheep;
case VILLAGER:
case CHICKEN:
case COW:
case POLAR_BEAR:
case MUSHROOM_COW:
case PIG:
restoreAgeable((Ageable) entity);
restoreLiving((LivingEntity) entity);
return entity;
// END AGEABLE //
case RABBIT:
if (this.dataByte != 0) {
((Rabbit) entity).setRabbitType(Type.values()[this.dataByte]);
}
restoreAgeable((Ageable) entity);
restoreLiving((LivingEntity) entity);
return entity;
case GUARDIAN:
if (this.dataByte != 0) {
((Guardian) entity).setElder(true);
}
restoreLiving((LivingEntity) entity);
return entity;
case SKELETON:
if (this.dataByte != 0) {
((Skeleton) entity).setSkeletonType(SkeletonType.values()[this.dataByte]);
}
storeLiving((LivingEntity) entity);
return entity;
case ARMOR_STAND:
// CHECK positions
ArmorStand stand = (ArmorStand) entity;
if (this.inventory[0] != null) {
stand.setItemInHand(this.inventory[0]);
}
if (this.inventory[1] != null) {
stand.setHelmet(this.inventory[1]);
}
if (this.inventory[2] != null) {
stand.setChestplate(this.inventory[2]);
}
if (this.inventory[3] != null) {
stand.setLeggings(this.inventory[3]);
}
if (this.inventory[4] != null) {
stand.setBoots(this.inventory[4]);
}
if (this.stand.head[0] != 0 || this.stand.head[1] != 0 || this.stand.head[2] != 0) {
EulerAngle pose = new EulerAngle(this.stand.head[0], this.stand.head[1], this.stand.head[2]);
stand.setHeadPose(pose);
}
if (this.stand.body[0] != 0 || this.stand.body[1] != 0 || this.stand.body[2] != 0) {
EulerAngle pose = new EulerAngle(this.stand.body[0], this.stand.body[1], this.stand.body[2]);
stand.setBodyPose(pose);
}
if (this.stand.leftLeg[0] != 0 || this.stand.leftLeg[1] != 0 || this.stand.leftLeg[2] != 0) {
EulerAngle pose = new EulerAngle(this.stand.leftLeg[0], this.stand.leftLeg[1], this.stand.leftLeg[2]);
stand.setLeftLegPose(pose);
}
if (this.stand.rightLeg[0] != 0 || this.stand.rightLeg[1] != 0 || this.stand.rightLeg[2] != 0) {
EulerAngle pose = new EulerAngle(this.stand.rightLeg[0], this.stand.rightLeg[1], this.stand.rightLeg[2]);
stand.setRightLegPose(pose);
}
if (this.stand.leftArm[0] != 0 || this.stand.leftArm[1] != 0 || this.stand.leftArm[2] != 0) {
EulerAngle pose = new EulerAngle(this.stand.leftArm[0], this.stand.leftArm[1], this.stand.leftArm[2]);
stand.setLeftArmPose(pose);
}
if (this.stand.rightArm[0] != 0 || this.stand.rightArm[1] != 0 || this.stand.rightArm[2] != 0) {
EulerAngle pose = new EulerAngle(this.stand.rightArm[0], this.stand.rightArm[1], this.stand.rightArm[2]);
stand.setRightArmPose(pose);
}
if (this.stand.invisible) {
stand.setVisible(false);
}
if (this.stand.arms) {
stand.setArms(true);
}
if (this.stand.noPlate) {
stand.setBasePlate(false);
}
if (this.stand.small) {
stand.setSmall(true);
}
restoreLiving(stand);
return stand;
case BAT:
if (this.dataByte != 0) {
((Bat) entity).setAwake(true);
}
restoreLiving((LivingEntity) entity);
return entity;
case ENDER_DRAGON:
if (this.dataByte != 0) {
((EnderDragon) entity).setPhase(EnderDragon.Phase.values()[this.dataByte]);
}
restoreLiving((LivingEntity) entity);
return entity;
case ENDERMITE:
case GHAST:
case MAGMA_CUBE:
case SQUID:
case PIG_ZOMBIE:
case ZOMBIE:
case WITHER:
case WITCH:
case SPIDER:
case CAVE_SPIDER:
case SILVERFISH:
case GIANT:
case ENDERMAN:
case CREEPER:
case BLAZE:
case SNOWMAN:
case SHULKER:
restoreLiving((LivingEntity) entity);
return entity;
case IRON_GOLEM:
if (this.dataByte != 0) {
((IronGolem) entity).setPlayerCreated(true);
}
restoreLiving((LivingEntity) entity);
return entity;
// END LIVING
}
}
private byte getOrdinal(Object[] list, Object value) {
for (byte i = 0; i < list.length; i++) {
if (list[i].equals(value)) {
return i;
}
}
return 0;
}
@SuppressWarnings("deprecation")
@Override
public String toString() {
return String.format("[%s, x=%s, y=%s, z=%s]", type.getName(), x, y, z);
}
}

View File

@ -0,0 +1,12 @@
package com.plotsquared.bukkit.object.entity;
import org.bukkit.entity.Horse;
class HorseStats {
double jump;
boolean chest;
Horse.Variant variant;
Horse.Color color;
Horse.Style style;
}

View File

@ -0,0 +1,28 @@
package com.plotsquared.bukkit.object.entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import java.util.Collection;
class LivingEntityStats {
boolean loot;
String name;
boolean visible;
float health;
short air;
boolean persistent;
boolean leashed;
short leashX;
short leashY;
short leashZ;
boolean equipped;
ItemStack mainHand;
ItemStack helmet;
ItemStack boots;
ItemStack leggings;
ItemStack chestplate;
Collection<PotionEffect> potions;
ItemStack offHand;
}

View File

@ -2,7 +2,8 @@ package com.plotsquared.bukkit.object.entity;
import org.bukkit.entity.AnimalTamer; import org.bukkit.entity.AnimalTamer;
public class TameableStats { class TameableStats {
public AnimalTamer owner;
public boolean tamed; AnimalTamer owner;
boolean tamed;
} }

View File

@ -0,0 +1,145 @@
package com.plotsquared.bukkit.object.schematic;
import com.intellectualcrafters.jnbt.ByteTag;
import com.intellectualcrafters.jnbt.CompoundTag;
import com.intellectualcrafters.jnbt.ListTag;
import com.intellectualcrafters.jnbt.ShortTag;
import com.intellectualcrafters.jnbt.Tag;
import com.intellectualcrafters.plot.object.schematic.ItemType;
import com.intellectualcrafters.plot.util.MathMan;
import com.plotsquared.bukkit.util.BukkitUtil;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class StateWrapper {
public BlockState state = null;
public CompoundTag tag = null;
public StateWrapper(BlockState state) {
this.state = state;
}
public StateWrapper(CompoundTag tag) {
this.tag = tag;
}
public boolean restoreTag(String worldName, int x, int y, int z) {
if (this.tag == null) {
return false;
}
switch (this.tag.getString("id").toLowerCase()) {
case "chest":
List<Tag> itemsTag = this.tag.getListTag("Items").getValue();
int length = itemsTag.size();
short[] ids = new short[length];
byte[] datas = new byte[length];
byte[] amounts = new byte[length];
byte[] slots = new byte[length];
for (int i = 0; i < length; i++) {
Tag itemTag = itemsTag.get(i);
CompoundTag itemComp = (CompoundTag) itemTag;
short id = itemComp.getShort("id");
String idStr = itemComp.getString("id");
if (idStr != null && !MathMan.isInteger(idStr)) {
idStr = idStr.split(":")[1].toLowerCase();
id = (short) ItemType.getId(idStr);
}
ids[i] = id;
datas[i] = (byte) itemComp.getShort("Damage");
amounts[i] = itemComp.getByte("Count");
slots[i] = itemComp.getByte("Slot");
}
World world = BukkitUtil.getWorld(worldName);
Block block = world.getBlockAt(x, y, z);
if (block == null) {
return false;
}
BlockState state = block.getState();
if (state instanceof InventoryHolder) {
InventoryHolder holder = (InventoryHolder) state;
Inventory inv = holder.getInventory();
for (int i = 0; i < ids.length; i++) {
ItemStack item = new ItemStack(ids[i], amounts[i], datas[i]);
inv.addItem(item);
}
state.update(true);
return true;
}
}
return false;
}
public CompoundTag getTag() {
if (this.tag != null) {
return this.tag;
}
if (this.state instanceof InventoryHolder) {
InventoryHolder inv = (InventoryHolder) this.state;
ItemStack[] contents = inv.getInventory().getContents();
Map<String, Tag> values = new HashMap<>();
values.put("Items", new ListTag("Items", CompoundTag.class, serializeInventory(contents)));
return new CompoundTag(values);
}
return null;
}
public String getId() {
return "Chest";
}
public List<CompoundTag> serializeInventory(ItemStack[] items) {
List<CompoundTag> tags = new ArrayList<>();
for (int i = 0; i < items.length; ++i) {
if (items[i] != null) {
Map<String, Tag> tagData = serializeItem(items[i]);
tagData.put("Slot", new ByteTag("Slot", (byte) i));
tags.add(new CompoundTag(tagData));
}
}
return tags;
}
/*
* TODO: Move this into the sponge module!
*
public Map<String, Tag> serializeItem(final org.spongepowered.api.item.inventory.ItemStack item) {
final Map<String, Tag> data = new HashMap<String, Tag>();
// FIXME serialize sponge item
return data;
}
*/
public Map<String, Tag> serializeItem(ItemStack item) {
Map<String, Tag> data = new HashMap<>();
data.put("id", new ShortTag("id", (short) item.getTypeId()));
data.put("Damage", new ShortTag("Damage", item.getDurability()));
data.put("Count", new ByteTag("Count", (byte) item.getAmount()));
if (!item.getEnchantments().isEmpty()) {
List<CompoundTag> enchantmentList = new ArrayList<>();
for (Entry<Enchantment, Integer> entry : item.getEnchantments().entrySet()) {
Map<String, Tag> enchantment = new HashMap<>();
enchantment.put("id", new ShortTag("id", (short) entry.getKey().getId()));
enchantment.put("lvl", new ShortTag("lvl", entry.getValue().shortValue()));
enchantmentList.add(new CompoundTag(enchantment));
}
Map<String, Tag> auxData = new HashMap<>();
auxData.put("ench", new ListTag("ench", CompoundTag.class, enchantmentList));
data.put("tag", new CompoundTag("tag", auxData));
}
return data;
}
}

View File

@ -0,0 +1,119 @@
package com.plotsquared.bukkit.titles;
import com.plotsquared.bukkit.chat.Reflection;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class DefaultTitleManager extends TitleManager {
/**
* Create a new 1.8 title.
*
* @param title Title text
* @param subtitle Subtitle text
* @param fadeInTime Fade in time
* @param stayTime Stay on screen time
* @param fadeOutTime Fade out time
*/
DefaultTitleManager(String title, String subtitle, int fadeInTime, int stayTime, int fadeOutTime) {
super(title, subtitle, fadeInTime, stayTime, fadeOutTime);
}
/**
* Load spigot and NMS classes.
*/
@Override void loadClasses() {
this.packetTitle = Reflection.getNMSClass("PacketPlayOutTitle");
this.packetActions = Reflection.getNMSClass("EnumTitleAction");
this.chatBaseComponent = Reflection.getNMSClass("IChatBaseComponent");
this.nmsChatSerializer = Reflection.getNMSClass("ChatSerializer");
}
@Override public void send(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException {
if (this.packetTitle != null) {
// First reset previous settings
resetTitle(player);
// Send timings first
Object handle = getHandle(player);
Object connection = getField(handle.getClass(), "playerConnection").get(handle);
Object[] actions = this.packetActions.getEnumConstants();
Method sendPacket = getMethod(connection.getClass(), "sendPacket");
Object packet = this.packetTitle.getConstructor(this.packetActions, this.chatBaseComponent, Integer.TYPE, Integer.TYPE, Integer.TYPE)
.newInstance(actions[2], null, this.fadeInTime * (this.ticks ? 1 : 20),
this.stayTime * (this.ticks ? 1 : 20), this.fadeOutTime * (this.ticks ? 1 : 20));
// Send if set
if (this.fadeInTime != -1 && this.fadeOutTime != -1 && this.stayTime != -1) {
sendPacket.invoke(connection, packet);
}
// Send title
Object serialized = getMethod(this.nmsChatSerializer, "a", String.class).invoke(null,
"{text:\"" + ChatColor.translateAlternateColorCodes('&', this.getTitle()) + "\",color:" + this.titleColor.name().toLowerCase()
+ '}');
packet = this.packetTitle.getConstructor(this.packetActions, this.chatBaseComponent).newInstance(actions[0], serialized);
sendPacket.invoke(connection, packet);
if (!this.getSubtitle().isEmpty()) {
// Send subtitle if present
serialized = getMethod(this.nmsChatSerializer, "a", String.class).invoke(null,
"{text:\"" + ChatColor.translateAlternateColorCodes('&', this.getSubtitle()) + "\",color:" + this.subtitleColor.name()
.toLowerCase() + '}');
packet = this.packetTitle.getConstructor(this.packetActions, this.chatBaseComponent).newInstance(actions[1], serialized);
sendPacket.invoke(connection, packet);
}
}
}
@Override
public void clearTitle(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException {
// Send timings first
Object handle = getHandle(player);
Object connection = getField(handle.getClass(), "playerConnection").get(handle);
Object[] actions = this.packetActions.getEnumConstants();
Method sendPacket = getMethod(connection.getClass(), "sendPacket");
Object packet = this.packetTitle.getConstructor(this.packetActions, this.chatBaseComponent).newInstance(actions[3], null);
sendPacket.invoke(connection, packet);
}
/**
* Reset the title settings.
*
* @param player Player
* @throws SecurityException
* @throws ReflectiveOperationException
* @throws SecurityException
*/
@Override
public void resetTitle(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException {
// Send timings first
Object handle = getHandle(player);
Object connection = getField(handle.getClass(), "playerConnection").get(handle);
Object[] actions = this.packetActions.getEnumConstants();
Method sendPacket = getMethod(connection.getClass(), "sendPacket");
Object packet = this.packetTitle.getConstructor(this.packetActions, this.chatBaseComponent).newInstance(actions[4], null);
sendPacket.invoke(connection, packet);
}
Field getField(Class<?> clazz, String name) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException | SecurityException e) {
e.printStackTrace();
return null;
}
}
Method getMethod(Class<?> clazz, String name, Class<?>... args) {
for (Method m : clazz.getMethods()) {
if (m.getName().equals(name) && (args.length == 0 || classListEqual(args, m.getParameterTypes()))) {
m.setAccessible(true);
return m;
}
}
return null;
}
}

View File

@ -0,0 +1,70 @@
package com.plotsquared.bukkit.titles;
import com.plotsquared.bukkit.chat.Reflection;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.lang.reflect.Method;
public class DefaultTitleManager_183 extends DefaultTitleManager {
/**
* Create a new 1.8 title.
*
* @param title Title text
* @param subtitle Subtitle text
* @param fadeInTime Fade in time
* @param stayTime Stay on screen time
* @param fadeOutTime Fade out time
*/
DefaultTitleManager_183(String title, String subtitle, int fadeInTime, int stayTime, int fadeOutTime) {
super(title, subtitle, fadeInTime, stayTime, fadeOutTime);
}
/**
* Load spigot and NMS classes.
*/
@Override
void loadClasses() {
this.packetTitle = Reflection.getNMSClass("PacketPlayOutTitle");
this.chatBaseComponent = Reflection.getNMSClass("IChatBaseComponent");
this.packetActions = Reflection.getNMSClass("PacketPlayOutTitle$EnumTitleAction");
this.nmsChatSerializer = Reflection.getNMSClass("IChatBaseComponent$ChatSerializer");
}
@Override
public void send(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException {
if (this.packetTitle != null) {
// First reset previous settings
resetTitle(player);
// Send timings first
Object handle = getHandle(player);
Object connection = getField(handle.getClass(), "playerConnection").get(handle);
Object[] actions = this.packetActions.getEnumConstants();
Method sendPacket = getMethod(connection.getClass(), "sendPacket");
Object packet = this.packetTitle
.getConstructor(this.packetActions, this.chatBaseComponent, Integer.TYPE, Integer.TYPE, Integer.TYPE)
.newInstance(actions[2], null,
this.fadeInTime * (this.ticks ? 1 : 20),
this.stayTime * (this.ticks ? 1 : 20), this.fadeOutTime * (this.ticks ? 1 : 20));
// Send if set
if ((this.fadeInTime != -1) && (this.fadeOutTime != -1) && (this.stayTime != -1)) {
sendPacket.invoke(connection, packet);
}
// Send title
Object serialized = getMethod(this.nmsChatSerializer, "a", String.class).invoke(null,
"{text:\"" + ChatColor.translateAlternateColorCodes('&', this.getTitle()) + "\",color:" + this.titleColor.name().toLowerCase()
+ "}");
packet = this.packetTitle.getConstructor(this.packetActions, this.chatBaseComponent).newInstance(actions[0], serialized);
sendPacket.invoke(connection, packet);
if (!this.getSubtitle().isEmpty()) {
// Send subtitle if present
serialized = getMethod(this.nmsChatSerializer, "a", String.class).invoke(null,
"{text:\"" + ChatColor.translateAlternateColorCodes('&', this.getSubtitle()) + "\",color:" + this.subtitleColor.name()
.toLowerCase() + "}");
packet = this.packetTitle.getConstructor(this.packetActions, this.chatBaseComponent).newInstance(actions[1], serialized);
sendPacket.invoke(connection, packet);
}
}
}
}

View File

@ -0,0 +1,32 @@
package com.plotsquared.bukkit.titles;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.AbstractTitle;
import com.plotsquared.bukkit.object.BukkitPlayer;
import com.plotsquared.bukkit.util.BukkitVersion;
import org.bukkit.entity.Player;
@SuppressWarnings("deprecation")
public class DefaultTitle_111 extends AbstractTitle {
private final boolean valid;
public DefaultTitle_111() {
this.valid = PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_11_0);
}
@Override
public void sendTitle(PlotPlayer player, String head, String sub, int in, int delay, int out) {
if (valid) {
try {
final Player playerObj = ((BukkitPlayer) player).player;
TitleManager_1_11 title = new TitleManager_1_11(head, sub, in, delay, out);
title.send(playerObj);
return;
} catch (Throwable ignored) {}
}
AbstractTitle.TITLE_CLASS = new DefaultTitle_180();
AbstractTitle.TITLE_CLASS.sendTitle(player, head, sub, in, delay, out);
}
}

View File

@ -4,14 +4,15 @@ import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.AbstractTitle; import com.intellectualcrafters.plot.util.AbstractTitle;
import com.plotsquared.bukkit.object.BukkitPlayer; import com.plotsquared.bukkit.object.BukkitPlayer;
public class DefaultTitle extends AbstractTitle { public class DefaultTitle_180 extends AbstractTitle {
@Override @Override
public void sendTitle(final PlotPlayer player, final String head, final String sub, final int in, final int delay, final int out) { public void sendTitle(PlotPlayer player, String head, String sub, int in, int delay, int out) {
try { try {
final DefaultTitleManager title = new DefaultTitleManager(head, sub, in, delay, out); DefaultTitleManager title = new DefaultTitleManager(head, sub, in, delay, out);
title.send(((BukkitPlayer) player).player); title.send(((BukkitPlayer) player).player);
} catch (Exception e) { } catch (Exception ignored) {
AbstractTitle.TITLE_CLASS = new DefaultTitle_183(); AbstractTitle.TITLE_CLASS = new DefaultTitle_19();
AbstractTitle.TITLE_CLASS.sendTitle(player, head, sub, in, delay, out); AbstractTitle.TITLE_CLASS.sendTitle(player, head, sub, in, delay, out);
} }
} }

View File

@ -5,12 +5,13 @@ import com.intellectualcrafters.plot.util.AbstractTitle;
import com.plotsquared.bukkit.object.BukkitPlayer; import com.plotsquared.bukkit.object.BukkitPlayer;
public class DefaultTitle_183 extends AbstractTitle { public class DefaultTitle_183 extends AbstractTitle {
@Override @Override
public void sendTitle(final PlotPlayer player, final String head, final String sub, final int in, final int delay, final int out) { public void sendTitle(PlotPlayer player, String head, String sub, int in, int delay, int out) {
try { try {
final DefaultTitleManager_183 title = new DefaultTitleManager_183(head, sub, in, delay, out); DefaultTitleManager_183 title = new DefaultTitleManager_183(head, sub, in, delay, out);
title.send(((BukkitPlayer) player).player); title.send(((BukkitPlayer) player).player);
} catch (final Throwable e) { } catch (Exception ignored) {
AbstractTitle.TITLE_CLASS = new HackTitle(); AbstractTitle.TITLE_CLASS = new HackTitle();
AbstractTitle.TITLE_CLASS.sendTitle(player, head, sub, in, delay, out); AbstractTitle.TITLE_CLASS.sendTitle(player, head, sub, in, delay, out);
} }

View File

@ -0,0 +1,28 @@
package com.plotsquared.bukkit.titles;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.AbstractTitle;
import com.intellectualcrafters.plot.util.TaskManager;
import com.plotsquared.bukkit.object.BukkitPlayer;
import org.bukkit.entity.Player;
@SuppressWarnings("deprecation")
public class DefaultTitle_19 extends AbstractTitle {
@Override
public void sendTitle(PlotPlayer player, String head, String sub, int in, int delay, int out) {
try {
final Player playerObj = ((BukkitPlayer) player).player;
playerObj.sendTitle(head, sub);
TaskManager.runTaskLater(new Runnable() {
@Override
public void run() {
playerObj.sendTitle("", "");
}
}, delay * 20);
} catch (Throwable ignored) {
AbstractTitle.TITLE_CLASS = new DefaultTitle_183();
AbstractTitle.TITLE_CLASS.sendTitle(player, head, sub, in, delay, out);
}
}
}

View File

@ -7,12 +7,13 @@ import com.intellectualcrafters.plot.util.AbstractTitle;
import com.plotsquared.bukkit.object.BukkitPlayer; import com.plotsquared.bukkit.object.BukkitPlayer;
public class HackTitle extends AbstractTitle { public class HackTitle extends AbstractTitle {
@Override @Override
public void sendTitle(final PlotPlayer player, final String head, final String sub, final int in, final int delay, final int out) { public void sendTitle(PlotPlayer player, String head, String sub, int in, int delay, int out) {
try { try {
final HackTitleManager title = new HackTitleManager(head, sub, in, delay, out); HackTitleManager title = new HackTitleManager(head, sub, in, delay, out);
title.send(((BukkitPlayer) player).player); title.send(((BukkitPlayer) player).player);
} catch (final Throwable e) { } catch (Exception ignored) {
PS.debug("&cYour server version does not support titles!"); PS.debug("&cYour server version does not support titles!");
Settings.TITLES = false; Settings.TITLES = false;
AbstractTitle.TITLE_CLASS = null; AbstractTitle.TITLE_CLASS = null;

View File

@ -0,0 +1,165 @@
package com.plotsquared.bukkit.titles;
import com.plotsquared.bukkit.chat.Reflection;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class HackTitleManager extends TitleManager {
/**
* Create a new 1.8 title.
*
* @param title Title text
* @param subtitle Subtitle text
* @param fadeInTime Fade in time
* @param stayTime Stay on screen time
* @param fadeOutTime Fade out time
*/
HackTitleManager(String title, String subtitle, int fadeInTime, int stayTime, int fadeOutTime) {
super(title, subtitle, fadeInTime, stayTime, fadeOutTime);
}
/**
* Load spigot and NMS classes.
*/
@Override
void loadClasses() {
this.packetTitle = getClass("org.spigotmc.ProtocolInjector$PacketTitle");
this.packetActions = getClass("org.spigotmc.ProtocolInjector$PacketTitle$Action");
this.nmsChatSerializer = Reflection.getNMSClass("ChatSerializer");
}
@Override public void send(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException {
if ((getProtocolVersion(player) >= 47) && isSpigot() && (this.packetTitle != null)) {
// First reset previous settings
resetTitle(player);
// Send timings first
Object handle = getHandle(player);
Object connection = getField(handle.getClass(), "playerConnection").get(handle);
Object[] actions = this.packetActions.getEnumConstants();
Method sendPacket = getMethod(connection.getClass(), "sendPacket");
Object packet = this.packetTitle.getConstructor(this.packetActions, Integer.TYPE, Integer.TYPE, Integer.TYPE).newInstance(actions[2],
this.fadeInTime * (this.ticks ? 1 : 20),
this.stayTime * (this.ticks ? 1 : 20),
this.fadeOutTime * (this.ticks ? 1 : 20));
// Send if set
if ((this.fadeInTime != -1) && (this.fadeOutTime != -1) && (this.stayTime != -1)) {
sendPacket.invoke(connection, packet);
}
// Send title
Object serialized = getMethod(this.nmsChatSerializer, "a", String.class).invoke(null,
"{text:\"" + ChatColor.translateAlternateColorCodes('&', this.getTitle()) + "\",color:" + this.titleColor.name().toLowerCase()
+ "}");
packet = this.packetTitle.getConstructor(this.packetActions, Reflection.getNMSClass("IChatBaseComponent"))
.newInstance(actions[0], serialized);
sendPacket.invoke(connection, packet);
if (!this.getSubtitle().isEmpty()) {
// Send subtitle if present
serialized = getMethod(this.nmsChatSerializer, "a", String.class).invoke(null,
"{text:\"" + ChatColor.translateAlternateColorCodes('&', this.getSubtitle()) + "\",color:" + this.subtitleColor.name()
.toLowerCase() + "}");
packet = this.packetTitle.getConstructor(this.packetActions, Reflection.getNMSClass("IChatBaseComponent"))
.newInstance(actions[1], serialized);
sendPacket.invoke(connection, packet);
}
}
}
@Override public void clearTitle(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException {
if ((getProtocolVersion(player) >= 47) && isSpigot()) {
// Send timings first
Object handle = getHandle(player);
Object connection = getField(handle.getClass(), "playerConnection").get(handle);
Object[] actions = this.packetActions.getEnumConstants();
Method sendPacket = getMethod(connection.getClass(), "sendPacket");
Object packet = this.packetTitle.getConstructor(this.packetActions).newInstance(actions[3]);
sendPacket.invoke(connection, packet);
}
}
@Override public void resetTitle(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException {
if ((getProtocolVersion(player) >= 47) && isSpigot()) {
// Send timings first
Object handle = getHandle(player);
Object connection = getField(handle.getClass(), "playerConnection").get(handle);
Object[] actions = this.packetActions.getEnumConstants();
Method sendPacket = getMethod(connection.getClass(), "sendPacket");
Object packet = this.packetTitle.getConstructor(this.packetActions).newInstance(actions[4]);
sendPacket.invoke(connection, packet);
}
}
/**
* Get the protocol version of the player.
*
* @param player Player
* @return Protocol version
* @throws IllegalArgumentException
* @throws ReflectiveOperationException
* @throws SecurityException
*/
private int getProtocolVersion(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException {
Object handle = getHandle(player);
Object connection = getField(handle.getClass(), "playerConnection").get(handle);
Object networkManager = getValue("networkManager", connection);
return (Integer) getMethod("getVersion", networkManager.getClass()).invoke(networkManager);
}
/**
* Check if running spigot.
*
* @return Spigot
*/
private boolean isSpigot() {
return Bukkit.getVersion().contains("Spigot");
}
/**
* Get class by url.
*
* @param namespace Namespace url
* @return Class
*/
private Class<?> getClass(String namespace) {
try {
return Class.forName(namespace);
} catch (ClassNotFoundException ignored) {}
return null;
}
private Field getField(String name, Class<?> clazz) throws NoSuchFieldException, SecurityException {
return clazz.getDeclaredField(name);
}
private Object getValue(String name, Object obj) throws ReflectiveOperationException, SecurityException, IllegalArgumentException {
Field f = getField(name, obj.getClass());
f.setAccessible(true);
return f.get(obj);
}
private Field getField(Class<?> clazz, String name) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field;
} catch (SecurityException | NoSuchFieldException e) {
e.printStackTrace();
return null;
}
}
private Method getMethod(Class<?> clazz, String name, Class<?>... args) {
for (Method m : clazz.getMethods()) {
if (m.getName().equals(name) && ((args.length == 0) || classListEqual(args, m.getParameterTypes()))) {
m.setAccessible(true);
return m;
}
}
return null;
}
}

View File

@ -0,0 +1,257 @@
package com.plotsquared.bukkit.titles;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public abstract class TitleManager {
private static final Map<Class<?>, Class<?>> CORRESPONDING_TYPES = new HashMap<>();
/* Title packet */
Class<?> packetTitle;
/* Title packet actions ENUM */
Class<?> packetActions;
/* Chat serializer */
Class<?> nmsChatSerializer;
Class<?> chatBaseComponent;
ChatColor titleColor = ChatColor.WHITE;
ChatColor subtitleColor = ChatColor.WHITE;
/* Title timings */
int fadeInTime = -1;
int stayTime = -1;
int fadeOutTime = -1;
boolean ticks = false;
/* Title text and color */
private String title = "";
/* Subtitle text and color */
private String subtitle = "";
/**
* Create a new 1.8 title.
*
* @param title Title text
* @param subtitle Subtitle text
* @param fadeInTime Fade in time
* @param stayTime Stay on screen time
* @param fadeOutTime Fade out time
*/
TitleManager(String title, String subtitle, int fadeInTime, int stayTime, int fadeOutTime) {
this.title = title;
this.subtitle = subtitle;
this.fadeInTime = fadeInTime;
this.stayTime = stayTime;
this.fadeOutTime = fadeOutTime;
loadClasses();
}
abstract void loadClasses();
/**
* Gets title text.
*
* @return Title text
*/
public final String getTitle() {
return this.title;
}
/**
* Sets the text for the title.
*
* @param title Title
*/
public final void setTitle(String title) {
this.title = title;
}
/**
* Gets the subtitle text.
*
* @return Subtitle text
*/
public final String getSubtitle() {
return this.subtitle;
}
/**
* Sets subtitle text.
*
* @param subtitle Subtitle text
*/
public final void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
/**
* Sets the title color.
*
* @param color Chat color
*/
public final void setTitleColor(ChatColor color) {
this.titleColor = color;
}
/**
* Sets the subtitle color.
*
* @param color Chat color
*/
public final void setSubtitleColor(ChatColor color) {
this.subtitleColor = color;
}
/**
* Sets title fade in time.
*
* @param time Time
*/
public final void setFadeInTime(int time) {
this.fadeInTime = time;
}
/**
* Sets title fade out time.
*
* @param time Time
*/
public final void setFadeOutTime(int time) {
this.fadeOutTime = time;
}
/**
* Sets title stay time.
*
* @param time Time
*/
public final void setStayTime(int time) {
this.stayTime = time;
}
/**
* Sets timings to ticks.
*/
public final void setTimingsToTicks() {
this.ticks = true;
}
/**
* Sets timings to seconds.
*/
public final void setTimingsToSeconds() {
this.ticks = false;
}
/**
* Sends the title to a player.
*
* @param player Player
* @throws IllegalArgumentException
* @throws ReflectiveOperationException
* @throws SecurityException
*/
public abstract void send(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException;
/**
* Broadcasts the title to all players.
*
* @throws Exception
*/
public final void broadcast() throws Exception {
for (Player player : Bukkit.getOnlinePlayers()) {
send(player);
}
}
/**
* Clears the title.
*
* @param player Player
* @throws IllegalArgumentException
* @throws ReflectiveOperationException
* @throws SecurityException
*/
public abstract void clearTitle(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException;
/**
* Resets the title settings.
*
* @param player Player
* @throws IllegalArgumentException
* @throws ReflectiveOperationException
* @throws SecurityException
*/
public abstract void resetTitle(Player player) throws IllegalArgumentException, ReflectiveOperationException, SecurityException;
private Class<?> getPrimitiveType(Class<?> clazz) {
if (CORRESPONDING_TYPES.containsKey(clazz)) {
return CORRESPONDING_TYPES.get(clazz);
} else {
return clazz;
}
}
private Class<?>[] toPrimitiveTypeArray(Class<?>[] classes) {
int a;
if (classes != null) {
a = classes.length;
} else {
a = 0;
}
Class<?>[] types = new Class<?>[a];
for (int i = 0; i < a; i++) {
types[i] = getPrimitiveType(classes[i]);
}
return types;
}
final Object getHandle(Object obj) {
try {
return getMethod("getHandle", obj.getClass()).invoke(obj);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
final Method getMethod(String name, Class<?> clazz, Class<?>... paramTypes) {
Class<?>[] t = toPrimitiveTypeArray(paramTypes);
for (Method m : clazz.getMethods()) {
Class<?>[] types = toPrimitiveTypeArray(m.getParameterTypes());
if (m.getName().equals(name) && equalsTypeArray(types, t)) {
return m;
}
}
return null;
}
private boolean equalsTypeArray(Class<?>[] a, Class<?>[] o) {
if (a.length != o.length) {
return false;
}
for (int i = 0; i < a.length; i++) {
if (!a[i].equals(o[i]) && !a[i].isAssignableFrom(o[i])) {
return false;
}
}
return true;
}
boolean classListEqual(Class<?>[] l1, Class<?>[] l2) {
if (l1.length != l2.length) {
return false;
}
boolean equal = true;
for (int i = 0; i < l1.length; i++) {
if (l1[i] != l2[i]) {
equal = false;
break;
}
}
return equal;
}
}

View File

@ -0,0 +1,526 @@
package com.plotsquared.bukkit.titles;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
/**
* Minecraft 1.8 Title
* For 1.11
*
* @author Maxim Van de Wynckel
* @version 1.1.0
*/
public class TitleManager_1_11 {
/* Title packet */
private static Class<?> packetTitle;
/* Title packet actions ENUM */
private static Class<?> packetActions;
/* Chat serializer */
private static Class<?> nmsChatSerializer;
private static Class<?> chatBaseComponent;
/* NMS player and connection */
private static Class<?> nmsPlayer;
private static Class<?> nmsPlayerConnection;
private static Field playerConnection;
private static Method sendPacket;
private static Class<?> obcPlayer;
private static Method methodPlayerGetHandle;
/* Title text and color */
private String title = "";
private ChatColor titleColor = ChatColor.WHITE;
/* Subtitle text and color */
private String subtitle = "";
private ChatColor subtitleColor = ChatColor.WHITE;
/* Title timings */
private int fadeInTime = -1;
private int stayTime = -1;
private int fadeOutTime = -1;
private boolean ticks = false;
private static final Map<Class<?>, Class<?>> CORRESPONDING_TYPES = new HashMap<Class<?>, Class<?>>();
public TitleManager_1_11() {
loadClasses();
}
/**
* Create a new 1.8 title
*
* @param title Title
*/
public TitleManager_1_11(String title) {
this.title = title;
loadClasses();
}
/**
* Create a new 1.8 title
*
* @param title Title text
* @param subtitle Subtitle text
*/
public TitleManager_1_11(String title, String subtitle) {
this.title = title;
this.subtitle = subtitle;
loadClasses();
}
/**
* Copy 1.8 title
*
* @param title Title
*/
public TitleManager_1_11(TitleManager_1_11 title) {
// Copy title
this.title = title.getTitle();
this.subtitle = title.getSubtitle();
this.titleColor = title.getTitleColor();
this.subtitleColor = title.getSubtitleColor();
this.fadeInTime = title.getFadeInTime();
this.fadeOutTime = title.getFadeOutTime();
this.stayTime = title.getStayTime();
this.ticks = title.isTicks();
loadClasses();
}
/**
* Create a new 1.8 title
*
* @param title Title text
* @param subtitle Subtitle text
* @param fadeInTime Fade in time
* @param stayTime Stay on screen time
* @param fadeOutTime Fade out time
*/
public TitleManager_1_11(String title, String subtitle, int fadeInTime, int stayTime, int fadeOutTime) {
this.title = title;
this.subtitle = subtitle;
this.fadeInTime = fadeInTime;
this.stayTime = stayTime;
this.fadeOutTime = fadeOutTime;
loadClasses();
}
/**
* Load spigot and NMS classes
*/
private void loadClasses() {
if (packetTitle == null) {
packetTitle = getNMSClass("PacketPlayOutTitle");
packetActions = getNMSClass("PacketPlayOutTitle$EnumTitleAction");
chatBaseComponent = getNMSClass("IChatBaseComponent");
nmsChatSerializer = getNMSClass("ChatComponentText");
nmsPlayer = getNMSClass("EntityPlayer");
nmsPlayerConnection = getNMSClass("PlayerConnection");
playerConnection = getField(nmsPlayer,
"playerConnection");
sendPacket = getMethod(nmsPlayerConnection, "sendPacket");
obcPlayer = getOBCClass("entity.CraftPlayer");
methodPlayerGetHandle = getMethod("getHandle", obcPlayer);
}
}
/**
* Set title text
*
* @param title Title
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Get title text
*
* @return Title text
*/
public String getTitle() {
return this.title;
}
/**
* Set subtitle text
*
* @param subtitle Subtitle text
*/
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
/**
* Get subtitle text
*
* @return Subtitle text
*/
public String getSubtitle() {
return this.subtitle;
}
/**
* Set the title color
*
* @param color Chat color
*/
public void setTitleColor(ChatColor color) {
this.titleColor = color;
}
/**
* Set the subtitle color
*
* @param color Chat color
*/
public void setSubtitleColor(ChatColor color) {
this.subtitleColor = color;
}
/**
* Set title fade in time
*
* @param time Time
*/
public void setFadeInTime(int time) {
this.fadeInTime = time;
}
/**
* Set title fade out time
*
* @param time Time
*/
public void setFadeOutTime(int time) {
this.fadeOutTime = time;
}
/**
* Set title stay time
*
* @param time Time
*/
public void setStayTime(int time) {
this.stayTime = time;
}
/**
* Set timings to ticks
*/
public void setTimingsToTicks() {
ticks = true;
}
/**
* Set timings to seconds
*/
public void setTimingsToSeconds() {
ticks = false;
}
/**
* Send the title to a player
*
* @param player Player
*/
public void send(Player player) {
if (packetTitle != null) {
// First reset previous settings
resetTitle(player);
try {
// Send timings first
Object handle = getHandle(player);
Object connection = playerConnection.get(handle);
Object[] actions = packetActions.getEnumConstants();
Object packet = packetTitle.getConstructor(packetActions,
chatBaseComponent, Integer.TYPE, Integer.TYPE,
Integer.TYPE).newInstance(actions[3], null,
fadeInTime * (ticks ? 1 : 20),
stayTime * (ticks ? 1 : 20),
fadeOutTime * (ticks ? 1 : 20));
// Send if set
if (fadeInTime != -1 && fadeOutTime != -1 && stayTime != -1)
sendPacket.invoke(connection, packet);
Object serialized;
if (!subtitle.equals("")) {
// Send subtitle if present
serialized = nmsChatSerializer.getConstructor(String.class)
.newInstance(subtitleColor +
ChatColor.translateAlternateColorCodes('&',
subtitle));
packet = packetTitle.getConstructor(packetActions,
chatBaseComponent).newInstance(actions[1],
serialized);
sendPacket.invoke(connection, packet);
}
// Send title
serialized = nmsChatSerializer.getConstructor(
String.class).newInstance(titleColor +
ChatColor.translateAlternateColorCodes('&', title));
packet = packetTitle.getConstructor(packetActions,
chatBaseComponent).newInstance(actions[0], serialized);
sendPacket.invoke(connection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void updateTimes(Player player) {
if (TitleManager_1_11.packetTitle != null) {
try {
Object handle = getHandle(player);
Object connection = playerConnection.get(handle);
Object[] actions = TitleManager_1_11.packetActions.getEnumConstants();
Object packet = TitleManager_1_11.packetTitle.getConstructor(
new Class[]{TitleManager_1_11.packetActions, chatBaseComponent,
Integer.TYPE, Integer.TYPE, Integer.TYPE})
.newInstance(
actions[3],
null,
this.fadeInTime
* (this.ticks ? 1 : 20),
this.stayTime
* (this.ticks ? 1 : 20),
this.fadeOutTime
* (this.ticks ? 1 : 20));
if ((this.fadeInTime != -1) && (this.fadeOutTime != -1)
&& (this.stayTime != -1)) {
sendPacket.invoke(connection, packet);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void updateTitle(Player player) {
if (TitleManager_1_11.packetTitle != null) {
try {
Object handle = getHandle(player);
Object connection = getField(handle.getClass(),
"playerConnection").get(handle);
Object[] actions = TitleManager_1_11.packetActions.getEnumConstants();
Method sendPacket = getMethod(connection.getClass(),
"sendPacket");
Object serialized = nmsChatSerializer.getConstructor(
String.class)
.newInstance(titleColor +
ChatColor.translateAlternateColorCodes('&',
this.title));
Object packet = TitleManager_1_11.packetTitle
.getConstructor(
new Class[]{TitleManager_1_11.packetActions,
chatBaseComponent}).newInstance(
actions[0], serialized);
sendPacket.invoke(connection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void updateSubtitle(Player player) {
if (TitleManager_1_11.packetTitle != null) {
try {
Object handle = getHandle(player);
Object connection = playerConnection.get(handle);
Object[] actions = TitleManager_1_11.packetActions.getEnumConstants();
Object serialized = nmsChatSerializer.getConstructor(
String.class)
.newInstance(subtitleColor +
ChatColor.translateAlternateColorCodes('&',
this.subtitle));
Object packet = TitleManager_1_11.packetTitle
.getConstructor(
new Class[]{TitleManager_1_11.packetActions,
chatBaseComponent}).newInstance(
actions[1], serialized);
sendPacket.invoke(connection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Broadcast the title to all players
*/
public void broadcast() {
for (Player p : Bukkit.getOnlinePlayers()) {
send(p);
}
}
/**
* Clear the title
*
* @param player Player
*/
public void clearTitle(Player player) {
try {
// Send timings first
Object handle = getHandle(player);
Object connection = playerConnection.get(handle);
Object[] actions = packetActions.getEnumConstants();
Object packet = packetTitle.getConstructor(packetActions,
chatBaseComponent).newInstance(actions[4], null);
sendPacket.invoke(connection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Reset the title settings
*
* @param player Player
*/
public void resetTitle(Player player) {
try {
// Send timings first
Object handle = getHandle(player);
Object connection = playerConnection.get(handle);
Object[] actions = packetActions.getEnumConstants();
Object packet = packetTitle.getConstructor(packetActions,
chatBaseComponent).newInstance(actions[5], null);
sendPacket.invoke(connection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
private Class<?> getPrimitiveType(Class<?> clazz) {
return CORRESPONDING_TYPES.containsKey(clazz) ? CORRESPONDING_TYPES
.get(clazz) : clazz;
}
private Class<?>[] toPrimitiveTypeArray(Class<?>[] classes) {
int a = classes != null ? classes.length : 0;
Class<?>[] types = new Class<?>[a];
for (int i = 0; i < a; i++)
types[i] = getPrimitiveType(classes[i]);
return types;
}
private static boolean equalsTypeArray(Class<?>[] a, Class<?>[] o) {
if (a.length != o.length)
return false;
for (int i = 0; i < a.length; i++)
if (!a[i].equals(o[i]) && !a[i].isAssignableFrom(o[i]))
return false;
return true;
}
private Object getHandle(Player player) {
try {
return methodPlayerGetHandle.invoke(player);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private Method getMethod(String name, Class<?> clazz,
Class<?>... paramTypes) {
Class<?>[] t = toPrimitiveTypeArray(paramTypes);
for (Method m : clazz.getMethods()) {
Class<?>[] types = toPrimitiveTypeArray(m.getParameterTypes());
if (m.getName().equals(name) && equalsTypeArray(types, t))
return m;
}
return null;
}
private String getVersion() {
String name = Bukkit.getServer().getClass().getPackage().getName();
String version = name.substring(name.lastIndexOf('.') + 1) + ".";
return version;
}
private Class<?> getNMSClass(String className) {
String fullName = "net.minecraft.server." + getVersion() + className;
Class<?> clazz = null;
try {
clazz = Class.forName(fullName);
} catch (Exception e) {
e.printStackTrace();
}
return clazz;
}
private Class<?> getOBCClass(String className) {
String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
Class<?> clazz = null;
try {
clazz = Class.forName(fullName);
} catch (Exception e) {
e.printStackTrace();
}
return clazz;
}
private Field getField(Class<?> clazz, String name) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private Method getMethod(Class<?> clazz, String name, Class<?>... args) {
for (Method m : clazz.getMethods())
if (m.getName().equals(name)
&& (args.length == 0 || ClassListEqual(args,
m.getParameterTypes()))) {
m.setAccessible(true);
return m;
}
return null;
}
private boolean ClassListEqual(Class<?>[] l1, Class<?>[] l2) {
boolean equal = true;
if (l1.length != l2.length)
return false;
for (int i = 0; i < l1.length; i++)
if (l1[i] != l2[i]) {
equal = false;
break;
}
return equal;
}
public ChatColor getTitleColor() {
return titleColor;
}
public ChatColor getSubtitleColor() {
return subtitleColor;
}
public int getFadeInTime() {
return fadeInTime;
}
public int getFadeOutTime() {
return fadeOutTime;
}
public int getStayTime() {
return stayTime;
}
public boolean isTicks() {
return ticks;
}
}

View File

@ -0,0 +1,61 @@
package com.plotsquared.bukkit.util;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.object.ConsolePlayer;
import com.intellectualcrafters.plot.object.PlotMessage;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.ChatManager;
import com.plotsquared.bukkit.chat.FancyMessage;
import com.plotsquared.bukkit.object.BukkitPlayer;
import org.bukkit.ChatColor;
import java.util.ArrayList;
import java.util.List;
public class BukkitChatManager extends ChatManager<FancyMessage> {
@Override
public FancyMessage builder() {
return new FancyMessage("");
}
@Override
public void color(PlotMessage message, String color) {
message.$(this).color(ChatColor.getByChar(C.color(color).substring(1)));
}
@Override
public void tooltip(PlotMessage message, PlotMessage... tooltips) {
List<FancyMessage> lines = new ArrayList<>();
for (PlotMessage tooltip : tooltips) {
lines.add(tooltip.$(this));
}
message.$(this).formattedTooltip(lines);
}
@Override
public void command(PlotMessage message, String command) {
message.$(this).command(command);
}
@Override
public void text(PlotMessage message, String text) {
message.$(this).then(ChatColor.stripColor(text));
}
@Override
public void send(PlotMessage plotMessage, PlotPlayer player) {
if (player instanceof ConsolePlayer || !Settings.Chat.INTERACTIVE) {
player.sendMessage(plotMessage.$(this).toOldMessageFormat());
} else {
plotMessage.$(this).send(((BukkitPlayer) player).player);
}
}
@Override
public void suggest(PlotMessage plotMessage, String command) {
plotMessage.$(this).suggest(command);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
package com.plotsquared.bukkit.util;
import com.intellectualcrafters.plot.commands.MainCommand;
import com.intellectualcrafters.plot.object.ConsolePlayer;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.plotsquared.bukkit.commands.DebugUUID;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.ProxiedCommandSender;
import org.bukkit.command.RemoteConsoleCommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class BukkitCommand implements CommandExecutor, TabCompleter {
public BukkitCommand() {
new DebugUUID();
}
@Override
public boolean onCommand(CommandSender commandSender, Command command, String commandLabel, String[] args) {
if (commandSender instanceof Player) {
return MainCommand.onCommand(BukkitUtil.getPlayer((Player) commandSender), args);
}
if (commandSender instanceof ConsoleCommandSender || commandSender instanceof ProxiedCommandSender
|| commandSender instanceof RemoteConsoleCommandSender) {
return MainCommand.onCommand(ConsolePlayer.getConsole(), args);
}
return false;
}
@Override
public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args) {
if (!(commandSender instanceof Player)) {
return null;
}
PlotPlayer player = BukkitUtil.getPlayer((Player) commandSender);
if (args.length == 0) {
return Collections.singletonList("plots");
}
Collection objects = MainCommand.getInstance().tab(player, args, s.endsWith(" "));
if (objects == null) {
return null;
}
List<String> result = new ArrayList<>();
for (Object o : objects) {
result.add(o.toString());
}
return result.isEmpty() ? null : result;
}
}

View File

@ -0,0 +1,87 @@
package com.plotsquared.bukkit.util;
import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.EconHandler;
import com.plotsquared.bukkit.object.BukkitOfflinePlayer;
import com.plotsquared.bukkit.object.BukkitPlayer;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.plugin.RegisteredServiceProvider;
public class BukkitEconHandler extends EconHandler {
private Economy econ;
private Permission perms;
public boolean init() {
if (this.econ == null || this.perms == null) {
setupPermissions();
setupEconomy();
}
return this.econ != null && this.perms != null;
}
private boolean setupPermissions() {
RegisteredServiceProvider<Permission> permissionProvider = Bukkit.getServer().getServicesManager().getRegistration(Permission.class);
if (permissionProvider != null) {
this.perms = permissionProvider.getProvider();
}
return this.perms != null;
}
private boolean setupEconomy() {
if (Bukkit.getServer().getPluginManager().getPlugin("Vault") == null) {
return false;
}
RegisteredServiceProvider<Economy> economyProvider = Bukkit.getServer().getServicesManager().getRegistration(Economy.class);
if (economyProvider != null) {
this.econ = economyProvider.getProvider();
}
return this.econ != null;
}
@Override
public double getMoney(PlotPlayer player) {
double bal = super.getMoney(player);
if (Double.isNaN(bal)) {
return this.econ.getBalance(((BukkitPlayer) player).player);
}
return bal;
}
@Override
public void withdrawMoney(PlotPlayer player, double amount) {
this.econ.withdrawPlayer(((BukkitPlayer) player).player, amount);
}
@Override
public void depositMoney(PlotPlayer player, double amount) {
this.econ.depositPlayer(((BukkitPlayer) player).player, amount);
}
@Override
public void depositMoney(OfflinePlotPlayer player, double amount) {
this.econ.depositPlayer(((BukkitOfflinePlayer) player).player, amount);
}
@Override
public boolean hasPermission(String world, String player, String perm) {
return this.perms.playerHas(world, Bukkit.getOfflinePlayer(player), perm);
}
@Override
public double getBalance(PlotPlayer player) {
return this.econ.getBalance(player.getName());
}
public void setPermission(String world, String player, String perm, boolean value) {
if (value) {
this.perms.playerAdd(world, player, perm);
} else {
this.perms.playerRemove(world, player, perm);
}
}
}

View File

@ -18,6 +18,7 @@ import com.plotsquared.bukkit.events.PlayerPlotHelperEvent;
import com.plotsquared.bukkit.events.PlayerPlotTrustedEvent; import com.plotsquared.bukkit.events.PlayerPlotTrustedEvent;
import com.plotsquared.bukkit.events.PlayerTeleportToPlotEvent; import com.plotsquared.bukkit.events.PlayerTeleportToPlotEvent;
import com.plotsquared.bukkit.events.PlotClearEvent; import com.plotsquared.bukkit.events.PlotClearEvent;
import com.plotsquared.bukkit.events.PlotComponentSetEvent;
import com.plotsquared.bukkit.events.PlotDeleteEvent; import com.plotsquared.bukkit.events.PlotDeleteEvent;
import com.plotsquared.bukkit.events.PlotFlagAddEvent; import com.plotsquared.bukkit.events.PlotFlagAddEvent;
import com.plotsquared.bukkit.events.PlotFlagRemoveEvent; import com.plotsquared.bukkit.events.PlotFlagRemoveEvent;
@ -35,91 +36,96 @@ import java.util.UUID;
public class BukkitEventUtil extends EventUtil { public class BukkitEventUtil extends EventUtil {
public Player getPlayer(final PlotPlayer player) { public Player getPlayer(PlotPlayer player) {
if (player instanceof BukkitPlayer) { if (player instanceof BukkitPlayer) {
return ((BukkitPlayer) player).player; return ((BukkitPlayer) player).player;
} }
return null; return null;
} }
public boolean callEvent(final Event event) { public boolean callEvent(Event event) {
Bukkit.getServer().getPluginManager().callEvent(event); Bukkit.getServer().getPluginManager().callEvent(event);
return !(event instanceof Cancellable) || !((Cancellable) event).isCancelled(); return !(event instanceof Cancellable) || !((Cancellable) event).isCancelled();
} }
@Override @Override
public boolean callClaim(final PlotPlayer player, final Plot plot, final boolean auto) { public boolean callClaim(PlotPlayer player, Plot plot, boolean auto) {
return callEvent(new PlayerClaimPlotEvent(getPlayer(player), plot, auto)); return callEvent(new PlayerClaimPlotEvent(getPlayer(player), plot, auto));
} }
@Override @Override
public boolean callTeleport(final PlotPlayer player, final Location from, final Plot plot) { public boolean callTeleport(PlotPlayer player, Location from, Plot plot) {
return callEvent(new PlayerTeleportToPlotEvent(getPlayer(player), from, plot)); return callEvent(new PlayerTeleportToPlotEvent(getPlayer(player), from, plot));
} }
@Override @Override
public boolean callClear(final Plot plot) { public boolean callComponentSet(Plot plot, String component) {
return callEvent(new PlotComponentSetEvent(plot, component));
}
@Override
public boolean callClear(Plot plot) {
return callEvent(new PlotClearEvent(plot)); return callEvent(new PlotClearEvent(plot));
} }
@Override @Override
public void callDelete(final Plot plot) { public void callDelete(Plot plot) {
callEvent(new PlotDeleteEvent(plot)); callEvent(new PlotDeleteEvent(plot));
} }
@Override @Override
public boolean callFlagAdd(final Flag flag, final Plot plot) { public boolean callFlagAdd(Flag flag, Plot plot) {
return callEvent(new PlotFlagAddEvent(flag, plot)); return callEvent(new PlotFlagAddEvent(flag, plot));
} }
@Override @Override
public boolean callFlagRemove(final Flag flag, final Plot plot) { public boolean callFlagRemove(Flag<?> flag, Plot plot, Object value) {
return callEvent(new PlotFlagRemoveEvent(flag, plot)); return callEvent(new PlotFlagRemoveEvent(flag, plot));
} }
@Override @Override
public boolean callMerge(final Plot plot, final ArrayList<PlotId> plots) { public boolean callMerge(Plot plot, ArrayList<PlotId> plots) {
return callEvent(new PlotMergeEvent(BukkitUtil.getWorld(plot.getArea().worldname), plot, plots)); return callEvent(new PlotMergeEvent(BukkitUtil.getWorld(plot.getWorldName()), plot, plots));
} }
@Override @Override
public boolean callUnlink(final PlotArea area, final ArrayList<PlotId> plots) { public boolean callUnlink(PlotArea area, ArrayList<PlotId> plots) {
return callEvent(new PlotUnlinkEvent(BukkitUtil.getWorld(area.worldname), area, plots)); return callEvent(new PlotUnlinkEvent(BukkitUtil.getWorld(area.worldname), area, plots));
} }
@Override @Override
public void callEntry(final PlotPlayer player, final Plot plot) { public void callEntry(PlotPlayer player, Plot plot) {
callEvent(new PlayerEnterPlotEvent(getPlayer(player), plot)); callEvent(new PlayerEnterPlotEvent(getPlayer(player), plot));
} }
@Override @Override
public void callLeave(final PlotPlayer player, final Plot plot) { public void callLeave(PlotPlayer player, Plot plot) {
callEvent(new PlayerLeavePlotEvent(getPlayer(player), plot)); callEvent(new PlayerLeavePlotEvent(getPlayer(player), plot));
} }
@Override @Override
public void callDenied(final PlotPlayer initiator, final Plot plot, final UUID player, final boolean added) { public void callDenied(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
callEvent(new PlayerPlotDeniedEvent(getPlayer(initiator), plot, player, added)); callEvent(new PlayerPlotDeniedEvent(getPlayer(initiator), plot, player, added));
} }
@Override @Override
public void callTrusted(final PlotPlayer initiator, final Plot plot, final UUID player, final boolean added) { public void callTrusted(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
callEvent(new PlayerPlotHelperEvent(getPlayer(initiator), plot, player, added));
}
@Override
public void callMember(final PlotPlayer initiator, final Plot plot, final UUID player, final boolean added) {
callEvent(new PlayerPlotTrustedEvent(getPlayer(initiator), plot, player, added)); callEvent(new PlayerPlotTrustedEvent(getPlayer(initiator), plot, player, added));
} }
@Override @Override
public boolean callFlagRemove(final Flag flag, final PlotCluster cluster) { public void callMember(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
callEvent(new PlayerPlotHelperEvent(getPlayer(initiator), plot, player, added));
}
@Override
public boolean callFlagRemove(Flag flag, Object object, PlotCluster cluster) {
return callEvent(new ClusterFlagRemoveEvent(flag, cluster)); return callEvent(new ClusterFlagRemoveEvent(flag, cluster));
} }
@Override @Override
public Rating callRating(final PlotPlayer player, final Plot plot, final Rating rating) { public Rating callRating(PlotPlayer player, Plot plot, Rating rating) {
final PlotRateEvent event = new PlotRateEvent(player, rating, plot); PlotRateEvent event = new PlotRateEvent(player, rating, plot);
Bukkit.getServer().getPluginManager().callEvent(event); Bukkit.getServer().getPluginManager().callEvent(event);
return event.getRating(); return event.getRating();
} }

View File

@ -1,21 +1,7 @@
package com.plotsquared.bukkit.util; package com.plotsquared.bukkit.util;
import java.util.HashSet;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import org.bukkit.material.Directional;
import org.bukkit.material.MaterialData;
import com.intellectualcrafters.plot.generator.HybridUtils; import com.intellectualcrafters.plot.generator.HybridUtils;
import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.PlotAnalysis;
import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.object.PlotBlock;
import com.intellectualcrafters.plot.object.RegionWrapper; import com.intellectualcrafters.plot.object.RegionWrapper;
import com.intellectualcrafters.plot.object.RunnableVal; import com.intellectualcrafters.plot.object.RunnableVal;
@ -23,6 +9,20 @@ import com.intellectualcrafters.plot.util.ChunkManager;
import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.MathMan; import com.intellectualcrafters.plot.util.MathMan;
import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.block.GlobalBlockQueue;
import com.intellectualcrafters.plot.util.block.LocalBlockQueue;
import com.intellectualcrafters.plot.util.expiry.PlotAnalysis;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import org.bukkit.material.Directional;
import org.bukkit.material.MaterialData;
import java.util.HashSet;
import java.util.Random;
public class BukkitHybridUtils extends HybridUtils { public class BukkitHybridUtils extends HybridUtils {
@ -43,6 +43,7 @@ public class BukkitHybridUtils extends HybridUtils {
TaskManager.runTaskAsync(new Runnable() { TaskManager.runTaskAsync(new Runnable() {
@Override @Override
public void run() { public void run() {
final LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(world, false);
final World worldObj = Bukkit.getWorld(world); final World worldObj = Bukkit.getWorld(world);
final ChunkGenerator gen = worldObj.getGenerator(); final ChunkGenerator gen = worldObj.getGenerator();
if (gen == null) { if (gen == null) {
@ -50,11 +51,11 @@ public class BukkitHybridUtils extends HybridUtils {
} }
final BiomeGrid nullBiomeGrid = new BiomeGrid() { final BiomeGrid nullBiomeGrid = new BiomeGrid() {
@Override @Override
public void setBiome(final int a, final int b, final Biome c) { public void setBiome(int a, int b, Biome c) {
} }
@Override @Override
public Biome getBiome(final int a, final int b) { public Biome getBiome(int a, int b) {
return null; return null;
} }
}; };
@ -72,13 +73,13 @@ public class BukkitHybridUtils extends HybridUtils {
final int ctz = tz >> 4; final int ctz = tz >> 4;
final Random r = new Random(); final Random r = new Random();
MainUtil.initCache(); MainUtil.initCache();
final int width = (tx - bx) + 1; final int width = tx - bx + 1;
final int length = (tz - bz) + 1; final int length = tz - bz + 1;
System.gc(); System.gc();
System.gc(); System.gc();
final short[][][] oldblocks = new short[256][width][length]; final short[][][] oldBlocks = new short[256][width][length];
final short[][][] newblocks = new short[256][width][length]; final short[][][] newBlocks = new short[256][width][length];
final Runnable run = new Runnable() { final Runnable run = new Runnable() {
@Override @Override
@ -87,38 +88,38 @@ public class BukkitHybridUtils extends HybridUtils {
@Override @Override
public void run(int[] value) { public void run(int[] value) {
// [chunkx, chunkz, pos1x, pos1z, pos2x, pos2z, isedge] // [chunkx, chunkz, pos1x, pos1z, pos2x, pos2z, isedge]
final int X = value[0]; int X = value[0];
final int Z = value[1]; int Z = value[1];
final short[][] result = gen.generateExtBlockSections(worldObj, r, X, Z, nullBiomeGrid); short[][] result = gen.generateExtBlockSections(worldObj, r, X, Z, nullBiomeGrid);
final int xb = ((X) << 4) - bx; int xb = (X << 4) - bx;
final int zb = ((Z) << 4) - bz; int zb = (Z << 4) - bz;
for (int i = 0; i < result.length; i++) { for (int i = 0; i < result.length; i++) {
if (result[i] == null) { if (result[i] == null) {
for (int j = 0; j < 4096; j++) { for (int j = 0; j < 4096; j++) {
final int x = MainUtil.x_loc[i][j] + xb; int x = MainUtil.x_loc[i][j] + xb;
if ((x < 0) || (x >= width)) { if (x < 0 || x >= width) {
continue; continue;
} }
final int z = MainUtil.z_loc[i][j] + zb; int z = MainUtil.z_loc[i][j] + zb;
if ((z < 0) || (z >= length)) { if (z < 0 || z >= length) {
continue; continue;
} }
final int y = MainUtil.y_loc[i][j]; int y = MainUtil.y_loc[i][j];
oldblocks[y][x][z] = 0; oldBlocks[y][x][z] = 0;
} }
continue; continue;
} }
for (int j = 0; j < result[i].length; j++) { for (int j = 0; j < result[i].length; j++) {
final int x = MainUtil.x_loc[i][j] + xb; int x = MainUtil.x_loc[i][j] + xb;
if ((x < 0) || (x >= width)) { if (x < 0 || x >= width) {
continue; continue;
} }
final int z = MainUtil.z_loc[i][j] + zb; int z = MainUtil.z_loc[i][j] + zb;
if ((z < 0) || (z >= length)) { if (z < 0 || z >= length) {
continue; continue;
} }
final int y = MainUtil.y_loc[i][j]; int y = MainUtil.y_loc[i][j];
oldblocks[y][x][z] = result[i][j]; oldBlocks[y][x][z] = result[i][j];
} }
} }
@ -129,19 +130,19 @@ public class BukkitHybridUtils extends HybridUtils {
TaskManager.runTaskAsync(new Runnable() { TaskManager.runTaskAsync(new Runnable() {
@Override @Override
public void run() { public void run() {
final int size = width * length; int size = width * length;
final int[] changes = new int[size]; int[] changes = new int[size];
final int[] faces = new int[size]; int[] faces = new int[size];
final int[] data = new int[size]; int[] data = new int[size];
final int[] air = new int[size]; int[] air = new int[size];
final int[] variety = new int[size]; int[] variety = new int[size];
int i = 0; int i = 0;
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
for (int z = 0; z < length; z++) { for (int z = 0; z < length; z++) {
final HashSet<Short> types = new HashSet<>(); HashSet<Short> types = new HashSet<>();
for (int y = 0; y < 256; y++) { for (int y = 0; y < 256; y++) {
final short old = oldblocks[y][x][z]; short old = oldBlocks[y][x][z];
final short now = newblocks[y][x][z]; short now = newBlocks[y][x][z];
if (old != now) { if (old != now) {
changes[i]++; changes[i]++;
} }
@ -150,34 +151,36 @@ public class BukkitHybridUtils extends HybridUtils {
} else { } else {
// check vertices // check vertices
// modifications_adjacent // modifications_adjacent
if ((x > 0) && (z > 0) && (y > 0) && (x < (width - 1)) && (z < (length - 1)) && (y < 255)) { if (x > 0 && z > 0 && y > 0 && x < width - 1 && z < length - 1 && y < 255) {
if (newblocks[y - 1][x][z] == 0) { if (newBlocks[y - 1][x][z] == 0) {
faces[i]++; faces[i]++;
} }
if (newblocks[y][x - 1][z] == 0) { if (newBlocks[y][x - 1][z] == 0) {
faces[i]++; faces[i]++;
} }
if (newblocks[y][x][z - 1] == 0) { if (newBlocks[y][x][z - 1] == 0) {
faces[i]++; faces[i]++;
} }
if (newblocks[y + 1][x][z] == 0) { if (newBlocks[y + 1][x][z] == 0) {
faces[i]++; faces[i]++;
} }
if (newblocks[y][x + 1][z] == 0) { if (newBlocks[y][x + 1][z] == 0) {
faces[i]++; faces[i]++;
} }
if (newblocks[y][x][z + 1] == 0) { if (newBlocks[y][x][z + 1] == 0) {
faces[i]++; faces[i]++;
} }
} }
final Material material = Material.getMaterial(now); Material material = Material.getMaterial(now);
final Class<? extends MaterialData> md = material.getData(); if (material != null) {
Class<? extends MaterialData> md = material.getData();
if (md.equals(Directional.class)) { if (md.equals(Directional.class)) {
data[i] += 8; data[i] += 8;
} else if (!md.equals(MaterialData.class)) { } else if (!md.equals(MaterialData.class)) {
data[i]++; data[i]++;
} }
}
types.add(now); types.add(now);
} }
} }
@ -189,18 +192,18 @@ public class BukkitHybridUtils extends HybridUtils {
// put in analysis obj // put in analysis obj
// run whenDone // run whenDone
final PlotAnalysis analysis = new PlotAnalysis(); PlotAnalysis analysis = new PlotAnalysis();
analysis.changes = (int) (MathMan.getMean(changes) * 100); analysis.changes = (int) (MathMan.getMean(changes) * 100);
analysis.faces = (int) (MathMan.getMean(faces) * 100); analysis.faces = (int) (MathMan.getMean(faces) * 100);
analysis.data = (int) (MathMan.getMean(data) * 100); analysis.data = (int) (MathMan.getMean(data) * 100);
analysis.air = (int) (MathMan.getMean(air) * 100); analysis.air = (int) (MathMan.getMean(air) * 100);
analysis.variety = (int) (MathMan.getMean(variety) * 100); analysis.variety = (int) (MathMan.getMean(variety) * 100);
analysis.changes_sd = (int) (MathMan.getSD(changes, analysis.changes)); analysis.changes_sd = (int) MathMan.getSD(changes, analysis.changes);
analysis.faces_sd = (int) (MathMan.getSD(faces, analysis.faces)); analysis.faces_sd = (int) MathMan.getSD(faces, analysis.faces);
analysis.data_sd = (int) (MathMan.getSD(data, analysis.data)); analysis.data_sd = (int) MathMan.getSD(data, analysis.data);
analysis.air_sd = (int) (MathMan.getSD(air, analysis.air)); analysis.air_sd = (int) MathMan.getSD(air, analysis.air);
analysis.variety_sd = (int) (MathMan.getSD(variety, analysis.variety)); analysis.variety_sd = (int) MathMan.getSD(variety, analysis.variety);
System.gc(); System.gc();
System.gc(); System.gc();
whenDone.value = analysis; whenDone.value = analysis;
@ -218,48 +221,48 @@ public class BukkitHybridUtils extends HybridUtils {
@Override @Override
public void run(int[] value) { public void run(int[] value) {
final int X = value[0]; int X = value[0];
final int Z = value[1]; int Z = value[1];
worldObj.loadChunk(X, Z); worldObj.loadChunk(X, Z);
int minX; int minX;
int minZ;
int maxX;
int maxZ;
if (X == cbx) { if (X == cbx) {
minX = bx & 15; minX = bx & 15;
} else { } else {
minX = 0; minX = 0;
} }
int minZ;
if (Z == cbz) { if (Z == cbz) {
minZ = bz & 15; minZ = bz & 15;
} else { } else {
minZ = 0; minZ = 0;
} }
int maxX;
if (X == ctx) { if (X == ctx) {
maxX = tx & 15; maxX = tx & 15;
} else { } else {
maxX = 16; maxX = 16;
} }
int maxZ;
if (Z == ctz) { if (Z == ctz) {
maxZ = tz & 15; maxZ = tz & 15;
} else { } else {
maxZ = 16; maxZ = 16;
} }
final int cbx = X << 4; int cbx = X << 4;
final int cbz = Z << 4; int cbz = Z << 4;
final int xb = (cbx) - bx; int xb = cbx - bx;
final int zb = (cbz) - bz; int zb = cbz - bz;
for (int x = minX; x <= maxX; x++) { for (int x = minX; x <= maxX; x++) {
final int xx = cbx + x; int xx = cbx + x;
for (int z = minZ; z <= maxZ; z++) { for (int z = minZ; z <= maxZ; z++) {
final int zz = cbz + z; int zz = cbz + z;
for (int y = 0; y < 256; y++) { for (int y = 0; y < 256; y++) {
final Block block = worldObj.getBlockAt(xx, y, zz); PlotBlock block = queue.getBlock(xx, y, zz);
final int xr = xb + x; int xr = xb + x;
final int zr = zb + z; int zr = zb + z;
newblocks[y][xr][zr] = (short) block.getTypeId(); newBlocks[y][xr][zr] = block.id;
} }
} }
} }
@ -274,50 +277,4 @@ public class BukkitHybridUtils extends HybridUtils {
} }
}); });
} }
@Override
public int checkModified(final String worldname, final int x1, final int x2, final int y1, final int y2, final int z1, final int z2,
final PlotBlock[] blocks) {
final World world = BukkitUtil.getWorld(worldname);
int count = 0;
for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++) {
for (int z = z1; z <= z2; z++) {
final Block block = world.getBlockAt(x, y, z);
final int id = block.getTypeId();
boolean same = false;
for (final PlotBlock p : blocks) {
if (id == p.id) {
same = true;
break;
}
}
if (!same) {
count++;
}
}
}
}
return count;
}
@Override
public int get_ey(final String worldname, final int sx, final int ex, final int sz, final int ez, final int sy) {
final World world = BukkitUtil.getWorld(worldname);
final int maxY = world.getMaxHeight();
int ey = sy;
for (int x = sx; x <= ex; x++) {
for (int z = sz; z <= ez; z++) {
for (int y = sy; y < maxY; y++) {
if (y > ey) {
final Block block = world.getBlockAt(x, y, z);
if (block.getTypeId() != 0) {
ey = y;
}
}
}
}
}
return ey;
}
} }

View File

@ -19,11 +19,11 @@ import java.util.List;
public class BukkitInventoryUtil extends InventoryUtil { public class BukkitInventoryUtil extends InventoryUtil {
public static ItemStack getItem(final PlotItemStack item) { public static ItemStack getItem(PlotItemStack item) {
if (item == null) { if (item == null) {
return null; return null;
} }
final ItemStack stack = new ItemStack(item.id, item.amount, item.data); ItemStack stack = new ItemStack(item.id, item.amount, item.data);
ItemMeta meta = null; ItemMeta meta = null;
if (item.name != null) { if (item.name != null) {
meta = stack.getItemMeta(); meta = stack.getItemMeta();
@ -33,8 +33,8 @@ public class BukkitInventoryUtil extends InventoryUtil {
if (meta == null) { if (meta == null) {
meta = stack.getItemMeta(); meta = stack.getItemMeta();
} }
final List<String> lore = new ArrayList<>(); List<String> lore = new ArrayList<>();
for (final String entry : item.lore) { for (String entry : item.lore) {
lore.add(ChatColor.translateAlternateColorCodes('&', entry)); lore.add(ChatColor.translateAlternateColorCodes('&', entry));
} }
meta.setLore(lore); meta.setLore(lore);
@ -46,12 +46,12 @@ public class BukkitInventoryUtil extends InventoryUtil {
} }
@Override @Override
public void open(final PlotInventory inv) { public void open(PlotInventory inv) {
final BukkitPlayer bp = (BukkitPlayer) inv.player; BukkitPlayer bp = (BukkitPlayer) inv.player;
final Inventory inventory = Bukkit.createInventory(null, inv.size * 9, inv.getTitle()); Inventory inventory = Bukkit.createInventory(null, inv.size * 9, inv.getTitle());
final PlotItemStack[] items = inv.getItems(); PlotItemStack[] items = inv.getItems();
for (int i = 0; i < inv.size * 9; i++) { for (int i = 0; i < inv.size * 9; i++) {
final PlotItemStack item = items[i]; PlotItemStack item = items[i];
if (item != null) { if (item != null) {
inventory.setItem(i, getItem(item)); inventory.setItem(i, getItem(item));
} }
@ -61,19 +61,19 @@ public class BukkitInventoryUtil extends InventoryUtil {
} }
@Override @Override
public void close(final PlotInventory inv) { public void close(PlotInventory inv) {
if (!inv.isOpen()) { if (!inv.isOpen()) {
return; return;
} }
inv.player.deleteMeta("inventory"); inv.player.deleteMeta("inventory");
final BukkitPlayer bp = (BukkitPlayer) inv.player; BukkitPlayer bp = (BukkitPlayer) inv.player;
bp.player.closeInventory(); bp.player.closeInventory();
} }
@Override @Override
public void setItem(final PlotInventory inv, final int index, final PlotItemStack item) { public void setItem(PlotInventory inv, int index, PlotItemStack item) {
final BukkitPlayer bp = (BukkitPlayer) inv.player; BukkitPlayer bp = (BukkitPlayer) inv.player;
final InventoryView opened = bp.player.getOpenInventory(); InventoryView opened = bp.player.getOpenInventory();
if (!inv.isOpen()) { if (!inv.isOpen()) {
return; return;
} }
@ -81,22 +81,22 @@ public class BukkitInventoryUtil extends InventoryUtil {
bp.player.updateInventory(); bp.player.updateInventory();
} }
public PlotItemStack getItem(final ItemStack item) { public PlotItemStack getItem(ItemStack item) {
if (item == null) { if (item == null) {
return null; return null;
} }
final int id = item.getTypeId(); int id = item.getTypeId();
final short data = item.getDurability(); short data = item.getDurability();
final int amount = item.getAmount(); int amount = item.getAmount();
String name = null; String name = null;
String[] lore = null; String[] lore = null;
if (item.hasItemMeta()) { if (item.hasItemMeta()) {
final ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
if (meta.hasDisplayName()) { if (meta.hasDisplayName()) {
name = meta.getDisplayName(); name = meta.getDisplayName();
} }
if (meta.hasLore()) { if (meta.hasLore()) {
final List<String> itemLore = meta.getLore(); List<String> itemLore = meta.getLore();
lore = itemLore.toArray(new String[itemLore.size()]); lore = itemLore.toArray(new String[itemLore.size()]);
} }
} }
@ -104,10 +104,10 @@ public class BukkitInventoryUtil extends InventoryUtil {
} }
@Override @Override
public PlotItemStack[] getItems(final PlotPlayer player) { public PlotItemStack[] getItems(PlotPlayer player) {
final BukkitPlayer bp = (BukkitPlayer) player; BukkitPlayer bp = (BukkitPlayer) player;
final PlayerInventory inv = bp.player.getInventory(); PlayerInventory inv = bp.player.getInventory();
final PlotItemStack[] items = new PlotItemStack[36]; PlotItemStack[] items = new PlotItemStack[36];
for (int i = 0; i < 36; i++) { for (int i = 0; i < 36; i++) {
items[i] = getItem(inv.getItem(i)); items[i] = getItem(inv.getItem(i));
} }
@ -115,12 +115,12 @@ public class BukkitInventoryUtil extends InventoryUtil {
} }
@Override @Override
public boolean isOpen(final PlotInventory inv) { public boolean isOpen(PlotInventory inv) {
if (!inv.isOpen()) { if (!inv.isOpen()) {
return false; return false;
} }
final BukkitPlayer bp = (BukkitPlayer) inv.player; BukkitPlayer bp = (BukkitPlayer) inv.player;
final InventoryView opened = bp.player.getOpenInventory(); InventoryView opened = bp.player.getOpenInventory();
return inv.isOpen() && opened.getType() == InventoryType.CRAFTING && opened.getTitle() == null; return inv.isOpen() && opened.getType() == InventoryType.CRAFTING && opened.getTitle() == null;
} }
} }

View File

@ -1,39 +1,5 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// PlotSquared - A plot manager and world generator for the Bukkit API /
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
// /
// This program is free software; you can redistribute it and/or modify /
// it under the terms of the GNU General Public License as published by /
// the Free Software Foundation; either version 3 of the License, or /
// (at your option) any later version. /
// /
// This program is distributed in the hope that it will be useful, /
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
// GNU General Public License for more details. /
// /
// You should have received a copy of the GNU General Public License /
// along with this program; if not, write to the Free Software Foundation, /
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
// /
// You can contact us via: support@intellectualsites.com /
////////////////////////////////////////////////////////////////////////////////////////////////////
package com.plotsquared.bukkit.util; package com.plotsquared.bukkit.util;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import com.intellectualcrafters.jnbt.ByteArrayTag; import com.intellectualcrafters.jnbt.ByteArrayTag;
import com.intellectualcrafters.jnbt.CompoundTag; import com.intellectualcrafters.jnbt.CompoundTag;
import com.intellectualcrafters.jnbt.IntTag; import com.intellectualcrafters.jnbt.IntTag;
@ -48,13 +14,23 @@ import com.intellectualcrafters.plot.object.RunnableVal;
import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.SchematicHandler; import com.intellectualcrafters.plot.util.SchematicHandler;
import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.block.LocalBlockQueue;
import com.plotsquared.bukkit.object.schematic.StateWrapper; import com.plotsquared.bukkit.object.schematic.StateWrapper;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* Schematic Handler * Schematic Handler.
*
*/ */
public class BukkitSchematicHandler extends SchematicHandler { public class BukkitSchematicHandler extends SchematicHandler {
@ -67,11 +43,11 @@ public class BukkitSchematicHandler extends SchematicHandler {
// Main positions // Main positions
Location[] corners = MainUtil.getCorners(world, regions); Location[] corners = MainUtil.getCorners(world, regions);
final Location bot = corners[0]; final Location bot = corners[0];
final Location top = corners[1]; Location top = corners[1];
final int width = (top.getX() - bot.getX()) + 1; final int width = top.getX() - bot.getX() + 1;
final int height = (top.getY() - bot.getY()) + 1; int height = top.getY() - bot.getY() + 1;
final int length = (top.getZ() - bot.getZ()) + 1; final int length = top.getZ() - bot.getZ() + 1;
// Main Schematic tag // Main Schematic tag
final HashMap<String, Tag> schematic = new HashMap<>(); final HashMap<String, Tag> schematic = new HashMap<>();
schematic.put("Width", new ShortTag("Width", (short) width)); schematic.put("Width", new ShortTag("Width", (short) width));
@ -85,7 +61,7 @@ public class BukkitSchematicHandler extends SchematicHandler {
schematic.put("WEOffsetY", new IntTag("WEOffsetY", 0)); schematic.put("WEOffsetY", new IntTag("WEOffsetY", 0));
schematic.put("WEOffsetZ", new IntTag("WEOffsetZ", 0)); schematic.put("WEOffsetZ", new IntTag("WEOffsetZ", 0));
// Arrays of data types // Arrays of data types
final List<Tag> tileEntities = new ArrayList<>(); final List<CompoundTag> tileEntities = new ArrayList<>();
final byte[] blocks = new byte[width * height * length]; final byte[] blocks = new byte[width * height * length];
final byte[] blockData = new byte[width * height * length]; final byte[] blockData = new byte[width * height * length];
// Queue // Queue
@ -137,16 +113,16 @@ public class BukkitSchematicHandler extends SchematicHandler {
TaskManager.runTask(new Runnable() { TaskManager.runTask(new Runnable() {
@Override @Override
public void run() { public void run() {
final long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
while ((!chunks.isEmpty()) && ((System.currentTimeMillis() - start) < 20)) { while (!chunks.isEmpty() && System.currentTimeMillis() - start < 20) {
// save schematics // save schematics
final ChunkLoc chunk = chunks.remove(0); ChunkLoc chunk = chunks.remove(0);
final Chunk bc = worldObj.getChunkAt(chunk.x, chunk.z); Chunk bc = worldObj.getChunkAt(chunk.x, chunk.z);
if (!bc.load(false)) { if (!bc.load(false)) {
continue; continue;
} }
final int X = chunk.x; int X = chunk.x;
final int Z = chunk.z; int Z = chunk.z;
int xxb = X << 4; int xxb = X << 4;
int zzb = Z << 4; int zzb = Z << 4;
int xxt = xxb + 15; int xxt = xxb + 15;
@ -165,16 +141,16 @@ public class BukkitSchematicHandler extends SchematicHandler {
zzt = p2z; zzt = p2z;
} }
for (int y = sy; y <= Math.min(255, ey); y++) { for (int y = sy; y <= Math.min(255, ey); y++) {
final int ry = y - sy; int ry = y - sy;
final int i1 = (ry * width * length); int i1 = ry * width * length;
for (int z = zzb; z <= zzt; z++) { for (int z = zzb; z <= zzt; z++) {
final int rz = z - bz; int rz = z - bz;
final int i2 = i1 + (rz * width); int i2 = i1 + rz * width;
for (int x = xxb; x <= xxt; x++) { for (int x = xxb; x <= xxt; x++) {
final int rx = x - bx; int rx = x - bx;
final int index = i2 + rx; int index = i2 + rx;
final Block block = worldObj.getBlockAt(x, y, z); Block block = worldObj.getBlockAt(x, y, z);
final int id = block.getTypeId(); int id = block.getTypeId();
switch (id) { switch (id) {
case 0: case 0:
case 2: case 2:
@ -243,9 +219,8 @@ public class BukkitSchematicHandler extends SchematicHandler {
case 189: case 189:
case 190: case 190:
case 191: case 191:
case 192: { case 192:
break; break;
}
case 54: case 54:
case 130: case 130:
case 142: case 142:
@ -280,30 +255,25 @@ public class BukkitSchematicHandler extends SchematicHandler {
case 29: case 29:
case 33: case 33:
case 151: case 151:
case 178: { case 178:
// TODO implement fully // TODO implement fully
final BlockState state = block.getState(); BlockState state = block.getState();
if (state != null) { if (state != null) {
final StateWrapper wrapper = new StateWrapper(state); StateWrapper wrapper = new StateWrapper(state);
final CompoundTag rawTag = wrapper.getTag(); CompoundTag rawTag = wrapper.getTag();
if (rawTag != null) { if (rawTag != null) {
final Map<String, Tag> values = new HashMap<String, Tag>(); Map<String, Tag> values = new HashMap<>(rawTag.getValue());
for (final Entry<String, Tag> entry : rawTag.getValue().entrySet()) {
values.put(entry.getKey(), entry.getValue());
}
values.put("id", new StringTag("id", wrapper.getId())); values.put("id", new StringTag("id", wrapper.getId()));
values.put("x", new IntTag("x", x)); values.put("x", new IntTag("x", x));
values.put("y", new IntTag("y", y)); values.put("y", new IntTag("y", y));
values.put("z", new IntTag("z", z)); values.put("z", new IntTag("z", z));
final CompoundTag tileEntityTag = new CompoundTag(values); CompoundTag tileEntityTag = new CompoundTag(values);
tileEntities.add(tileEntityTag); tileEntities.add(tileEntityTag);
} }
} }
} default:
default: {
blockData[index] = block.getData(); blockData[index] = block.getData();
} }
}
// For optimization reasons, we are not supporting custom data types // For optimization reasons, we are not supporting custom data types
// Especially since the most likely reason beyond this range is modded servers in which the blocks // Especially since the most likely reason beyond this range is modded servers in which the blocks
// have NBT // have NBT
@ -334,7 +304,7 @@ public class BukkitSchematicHandler extends SchematicHandler {
} }
@Override @Override
public void restoreTag(CompoundTag ct, short x, short y, short z, Schematic schem) { public boolean restoreTile(LocalBlockQueue queue, CompoundTag ct, int x, int y, int z) {
new StateWrapper(ct).restoreTag(x, y, z, schem); return new StateWrapper(ct).restoreTag(queue.getWorld(), x, y, z);
} }
} }

View File

@ -9,18 +9,20 @@ import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.object.SetupObject; import com.intellectualcrafters.plot.object.SetupObject;
import com.intellectualcrafters.plot.util.SetupUtils; import com.intellectualcrafters.plot.util.SetupUtils;
import com.plotsquared.bukkit.generator.BukkitPlotGenerator; import com.plotsquared.bukkit.generator.BukkitPlotGenerator;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.WorldCreator;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
public class BukkitSetupUtils extends SetupUtils { public class BukkitSetupUtils extends SetupUtils {
@ -29,13 +31,14 @@ public class BukkitSetupUtils extends SetupUtils {
if (!SetupUtils.generators.isEmpty()) { if (!SetupUtils.generators.isEmpty()) {
return; return;
} }
final String testWorld = "CheckingPlotSquaredGenerator"; String testWorld = "CheckingPlotSquaredGenerator";
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) { for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
try {
if (plugin.isEnabled()) { if (plugin.isEnabled()) {
final ChunkGenerator generator = plugin.getDefaultWorldGenerator(testWorld, ""); ChunkGenerator generator = plugin.getDefaultWorldGenerator(testWorld, "");
if (generator != null) { if (generator != null) {
PS.get().removePlotAreas(testWorld); PS.get().removePlotAreas(testWorld);
final String name = plugin.getDescription().getName(); String name = plugin.getDescription().getName();
GeneratorWrapper<?> wrapped; GeneratorWrapper<?> wrapped;
if (generator instanceof GeneratorWrapper<?>) { if (generator instanceof GeneratorWrapper<?>) {
wrapped = (GeneratorWrapper<?>) generator; wrapped = (GeneratorWrapper<?>) generator;
@ -45,37 +48,62 @@ public class BukkitSetupUtils extends SetupUtils {
SetupUtils.generators.put(name, wrapped); SetupUtils.generators.put(name, wrapped);
} }
} }
} catch (Throwable e) { // Recover from third party generator error
e.printStackTrace();
}
} }
} }
@Override @Override
public String setupWorld(final SetupObject object) { public void unload(String worldName, boolean save) {
World world = Bukkit.getWorld(worldName);
if (world == null) {
return;
}
World dw = Bukkit.getWorlds().get(0);
for (Player player : world.getPlayers()) {
player.teleport(dw.getSpawnLocation());
}
if (save) {
for (Chunk chunk : world.getLoadedChunks()) {
chunk.unload(true, false);
}
} else {
for (Chunk chunk : world.getLoadedChunks()) {
chunk.unload(false, false);
}
}
Bukkit.unloadWorld(world, false);
}
@Override
public String setupWorld(SetupObject object) {
SetupUtils.manager.updateGenerators(); SetupUtils.manager.updateGenerators();
ConfigurationNode[] steps = object.step == null ? new ConfigurationNode[0] : object.step; ConfigurationNode[] steps = object.step == null ? new ConfigurationNode[0] : object.step;
final String world = object.world; String world = object.world;
int type = object.type; int type = object.type;
String worldPath = "worlds." + object.world; String worldPath = "worlds." + object.world;
if (!PS.get().config.contains(worldPath)) {
PS.get().config.createSection(worldPath);
}
ConfigurationSection worldSection = PS.get().config.getConfigurationSection(worldPath);
switch (type) { switch (type) {
case 2: { case 2: {
if (object.id != null) { if (object.id != null) {
String areaname = object.id + "-" + object.min + "-" + object.max; if (!PS.get().worlds.contains(worldPath)) {
String areaPath = "areas." + areaname; PS.get().worlds.createSection(worldPath);
}
ConfigurationSection worldSection = PS.get().worlds.getConfigurationSection(worldPath);
String areaName = object.id + "-" + object.min + "-" + object.max;
String areaPath = "areas." + areaName;
if (!worldSection.contains(areaPath)) { if (!worldSection.contains(areaPath)) {
worldSection.createSection(areaPath); worldSection.createSection(areaPath);
} }
ConfigurationSection areaSection = worldSection.getConfigurationSection(areaPath); ConfigurationSection areaSection = worldSection.getConfigurationSection(areaPath);
HashMap<String, Object> options = new HashMap<>(); HashMap<String, Object> options = new HashMap<>();
for (final ConfigurationNode step : steps) { for (ConfigurationNode step : steps) {
options.put(step.getConstant(), step.getValue()); options.put(step.getConstant(), step.getValue());
} }
options.put("generator.type", object.type); options.put("generator.type", object.type);
options.put("generator.terrain", object.terrain); options.put("generator.terrain", object.terrain);
options.put("generator.plugin", object.plotManager); options.put("generator.plugin", object.plotManager);
if ((object.setupGenerator != null) && !object.setupGenerator.equals(object.plotManager)) { if (object.setupGenerator != null && !object.setupGenerator.equals(object.plotManager)) {
options.put("generator.init", object.setupGenerator); options.put("generator.init", object.setupGenerator);
} }
for (Entry<String, Object> entry : options.entrySet()) { for (Entry<String, Object> entry : options.entrySet()) {
@ -91,42 +119,52 @@ public class BukkitSetupUtils extends SetupUtils {
} }
} }
} }
GeneratorWrapper<?> gen = generators.get(object.setupGenerator); GeneratorWrapper<?> gen = SetupUtils.generators.get(object.setupGenerator);
if ((gen != null) && gen.isFull()) { if (gen != null && gen.isFull()) {
object.setupGenerator = null; object.setupGenerator = null;
} }
break; break;
} }
case 1: { case 1: {
for (final ConfigurationNode step : steps) { if (!PS.get().worlds.contains(worldPath)) {
PS.get().worlds.createSection(worldPath);
}
ConfigurationSection worldSection = PS.get().worlds.getConfigurationSection(worldPath);
for (ConfigurationNode step : steps) {
worldSection.set(step.getConstant(), step.getValue()); worldSection.set(step.getConstant(), step.getValue());
} }
PS.get().config.set("worlds." + world + "." + "generator.type", object.type); PS.get().worlds.set("worlds." + world + ".generator.type", object.type);
PS.get().config.set("worlds." + world + "." + "generator.terrain", object.terrain); PS.get().worlds.set("worlds." + world + ".generator.terrain", object.terrain);
PS.get().config.set("worlds." + world + "." + "generator.plugin", object.plotManager); PS.get().worlds.set("worlds." + world + ".generator.plugin", object.plotManager);
if ((object.setupGenerator != null) && !object.setupGenerator.equals(object.plotManager)) { if (object.setupGenerator != null && !object.setupGenerator.equals(object.plotManager)) {
PS.get().config.set("worlds." + world + "." + "generator.init", object.setupGenerator); PS.get().worlds.set("worlds." + world + ".generator.init", object.setupGenerator);
} }
GeneratorWrapper<?> gen = generators.get(object.setupGenerator); GeneratorWrapper<?> gen = SetupUtils.generators.get(object.setupGenerator);
if ((gen != null) && gen.isFull()) { if (gen != null && gen.isFull()) {
object.setupGenerator = null; object.setupGenerator = null;
} }
break; break;
} }
case 0: { case 0: {
for (final ConfigurationNode step : steps) { if (steps.length != 0) {
if (!PS.get().worlds.contains(worldPath)) {
PS.get().worlds.createSection(worldPath);
}
ConfigurationSection worldSection = PS.get().worlds.getConfigurationSection(worldPath);
for (ConfigurationNode step : steps) {
worldSection.set(step.getConstant(), step.getValue()); worldSection.set(step.getConstant(), step.getValue());
} }
}
break; break;
} }
} }
try { try {
PS.get().config.save(PS.get().configFile); PS.get().worlds.save(PS.get().worldsFile);
} catch (final IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
if (object.setupGenerator != null) { if (object.setupGenerator != null) {
if ((Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null) && Bukkit.getPluginManager().getPlugin("Multiverse-Core") if (Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null && Bukkit.getPluginManager().getPlugin("Multiverse-Core")
.isEnabled()) { .isEnabled()) {
Bukkit.getServer() Bukkit.getServer()
.dispatchCommand(Bukkit.getServer().getConsoleSender(), "mv create " + world + " normal -g " + object.setupGenerator); .dispatchCommand(Bukkit.getServer().getConsoleSender(), "mv create " + world + " normal -g " + object.setupGenerator);
@ -135,65 +173,66 @@ public class BukkitSetupUtils extends SetupUtils {
return world; return world;
} }
} }
if ((Bukkit.getPluginManager().getPlugin("MultiWorld") != null) && Bukkit.getPluginManager().getPlugin("MultiWorld").isEnabled()) { if (Bukkit.getPluginManager().getPlugin("MultiWorld") != null && Bukkit.getPluginManager().getPlugin("MultiWorld").isEnabled()) {
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mw create " + world + " plugin:" + object.setupGenerator); Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mw create " + world + " plugin:" + object.setupGenerator);
setGenerator(world, object.setupGenerator); setGenerator(world, object.setupGenerator);
if (Bukkit.getWorld(world) != null) { if (Bukkit.getWorld(world) != null) {
return world; return world;
} }
} }
final WorldCreator wc = new WorldCreator(object.world); WorldCreator wc = new WorldCreator(object.world);
wc.generator(object.setupGenerator); wc.generator(object.setupGenerator);
wc.environment(Environment.NORMAL); wc.environment(Environment.NORMAL);
wc.type(WorldType.FLAT);
Bukkit.createWorld(wc); Bukkit.createWorld(wc);
setGenerator(world, object.setupGenerator); setGenerator(world, object.setupGenerator);
} else { } else {
if ((Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null) && Bukkit.getPluginManager().getPlugin("Multiverse-Core") if (Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null && Bukkit.getPluginManager().getPlugin("Multiverse-Core")
.isEnabled()) { .isEnabled()) {
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mv create " + world + " normal"); Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mv create " + world + " normal");
if (Bukkit.getWorld(world) != null) { if (Bukkit.getWorld(world) != null) {
return world; return world;
} }
} }
if ((Bukkit.getPluginManager().getPlugin("MultiWorld") != null) && Bukkit.getPluginManager().getPlugin("MultiWorld").isEnabled()) { if (Bukkit.getPluginManager().getPlugin("MultiWorld") != null && Bukkit.getPluginManager().getPlugin("MultiWorld").isEnabled()) {
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mw create " + world); Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mw create " + world);
if (Bukkit.getWorld(world) != null) { if (Bukkit.getWorld(world) != null) {
return world; return world;
} }
} }
Bukkit.createWorld(new WorldCreator(object.world).environment(World.Environment.NORMAL)); World bw = Bukkit.createWorld(new WorldCreator(object.world).environment(Environment.NORMAL));
} }
return object.world; return object.world;
} }
public void setGenerator(final String world, final String generator) { public void setGenerator(String world, String generator) {
if ((Bukkit.getWorlds().isEmpty()) || !Bukkit.getWorlds().get(0).getName().equals(world)) { if (Bukkit.getWorlds().isEmpty() || !Bukkit.getWorlds().get(0).getName().equals(world)) {
return; return;
} }
final File file = new File("bukkit.yml").getAbsoluteFile(); File file = new File("bukkit.yml").getAbsoluteFile();
final YamlConfiguration yml = YamlConfiguration.loadConfiguration(file); YamlConfiguration yml = YamlConfiguration.loadConfiguration(file);
yml.set("worlds." + world + ".generator", generator); yml.set("worlds." + world + ".generator", generator);
try { try {
yml.save(file); yml.save(file);
} catch (final IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override @Override
public String getGenerator(final PlotArea plotworld) { public String getGenerator(PlotArea plotArea) {
if (SetupUtils.generators.isEmpty()) { if (SetupUtils.generators.isEmpty()) {
updateGenerators(); updateGenerators();
} }
final World world = Bukkit.getWorld(plotworld.worldname); World world = Bukkit.getWorld(plotArea.worldname);
if (world == null) { if (world == null) {
return null; return null;
} }
final ChunkGenerator generator = world.getGenerator(); ChunkGenerator generator = world.getGenerator();
if (!(generator instanceof BukkitPlotGenerator)) { if (!(generator instanceof BukkitPlotGenerator)) {
return null; return null;
} }
for (final Entry<String, GeneratorWrapper<?>> entry : generators.entrySet()) { for (Entry<String, GeneratorWrapper<?>> entry : SetupUtils.generators.entrySet()) {
GeneratorWrapper<?> current = entry.getValue(); GeneratorWrapper<?> current = entry.getValue();
if (current.equals(generator)) { if (current.equals(generator)) {
return entry.getKey(); return entry.getKey();

View File

@ -0,0 +1,52 @@
package com.plotsquared.bukkit.util;
import com.intellectualcrafters.plot.util.TaskManager;
import com.plotsquared.bukkit.BukkitMain;
import org.bukkit.Bukkit;
public class BukkitTaskManager extends TaskManager {
private final BukkitMain bukkitMain;
public BukkitTaskManager(BukkitMain bukkitMain) {
this.bukkitMain = bukkitMain;
}
@Override
public int taskRepeat(Runnable runnable, int interval) {
return this.bukkitMain.getServer().getScheduler().scheduleSyncRepeatingTask(this.bukkitMain, runnable, interval, interval);
}
@SuppressWarnings("deprecation")
@Override
public int taskRepeatAsync(Runnable runnable, int interval) {
return this.bukkitMain.getServer().getScheduler().scheduleAsyncRepeatingTask(this.bukkitMain, runnable, interval, interval);
}
@Override
public void taskAsync(Runnable runnable) {
this.bukkitMain.getServer().getScheduler().runTaskAsynchronously(this.bukkitMain, runnable).getTaskId();
}
@Override
public void task(Runnable runnable) {
this.bukkitMain.getServer().getScheduler().runTask(this.bukkitMain, runnable).getTaskId();
}
@Override
public void taskLater(Runnable runnable, int delay) {
this.bukkitMain.getServer().getScheduler().runTaskLater(this.bukkitMain, runnable, delay).getTaskId();
}
@Override
public void taskLaterAsync(Runnable runnable, int delay) {
this.bukkitMain.getServer().getScheduler().runTaskLaterAsynchronously(this.bukkitMain, runnable, delay);
}
@Override
public void cancelTask(int task) {
if (task != -1) {
Bukkit.getScheduler().cancelTask(task);
}
}
}

View File

@ -7,11 +7,12 @@ import com.intellectualcrafters.plot.object.RegionWrapper;
import com.intellectualcrafters.plot.object.schematic.PlotItem; import com.intellectualcrafters.plot.object.schematic.PlotItem;
import com.intellectualcrafters.plot.util.MathMan; import com.intellectualcrafters.plot.util.MathMan;
import com.intellectualcrafters.plot.util.StringComparison; import com.intellectualcrafters.plot.util.StringComparison;
import com.intellectualcrafters.plot.util.StringMan;
import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.UUIDHandler; import com.intellectualcrafters.plot.util.UUIDHandler;
import com.intellectualcrafters.plot.util.WorldUtil; import com.intellectualcrafters.plot.util.WorldUtil;
import com.plotsquared.bukkit.object.BukkitPlayer; import com.plotsquared.bukkit.object.BukkitPlayer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
@ -32,9 +33,6 @@ import org.bukkit.material.Tree;
import org.bukkit.material.WoodenStep; import org.bukkit.material.WoodenStep;
import org.bukkit.material.Wool; import org.bukkit.material.Wool;
import java.util.Arrays;
import java.util.List;
public class BukkitUtil extends WorldUtil { public class BukkitUtil extends WorldUtil {
private static String lastString = null; private static String lastString = null;
@ -43,28 +41,28 @@ public class BukkitUtil extends WorldUtil {
private static Player lastPlayer = null; private static Player lastPlayer = null;
private static PlotPlayer lastPlotPlayer = null; private static PlotPlayer lastPlotPlayer = null;
public static void removePlayer(final String plr) { public static void removePlayer(String player) {
lastPlayer = null; lastPlayer = null;
lastPlotPlayer = null; lastPlotPlayer = null;
} }
public static PlotPlayer getPlayer(final OfflinePlayer op) { public static PlotPlayer getPlayer(OfflinePlayer op) {
if (op.isOnline()) { if (op.isOnline()) {
return getPlayer(op.getPlayer()); return getPlayer(op.getPlayer());
} }
final Player player = OfflinePlayerUtil.loadPlayer(op); Player player = OfflinePlayerUtil.loadPlayer(op);
player.loadData(); player.loadData();
return new BukkitPlayer(player, true); return new BukkitPlayer(player, true);
} }
public static PlotPlayer getPlayer(final Player player) { public static PlotPlayer getPlayer(Player player) {
if (player == lastPlayer) { if (player == lastPlayer) {
return lastPlotPlayer; return lastPlotPlayer;
} }
final String name = player.getName(); String name = player.getName();
final PlotPlayer pp = UUIDHandler.getPlayer(name); PlotPlayer plotPlayer = UUIDHandler.getPlayer(name);
if (pp != null) { if (plotPlayer != null) {
return pp; return plotPlayer;
} }
lastPlotPlayer = new BukkitPlayer(player); lastPlotPlayer = new BukkitPlayer(player);
UUIDHandler.getPlayers().put(name, lastPlotPlayer); UUIDHandler.getPlayers().put(name, lastPlotPlayer);
@ -72,84 +70,72 @@ public class BukkitUtil extends WorldUtil {
return lastPlotPlayer; return lastPlotPlayer;
} }
public static Location getLocation(final org.bukkit.Location loc) { public static Location getLocation(org.bukkit.Location location) {
return new Location(loc.getWorld().getName(), MathMan.roundInt(loc.getX()), MathMan.roundInt(loc.getY()), MathMan.roundInt(loc.getZ())); return new Location(location.getWorld().getName(), MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()),
MathMan.roundInt(location.getZ()));
} }
public static org.bukkit.Location getLocation(final Location loc) { public static org.bukkit.Location getLocation(Location location) {
return new org.bukkit.Location(getWorld(loc.getWorld()), loc.getX(), loc.getY(), loc.getZ()); return new org.bukkit.Location(getWorld(location.getWorld()), location.getX(), location.getY(), location.getZ());
} }
public static World getWorld(final String string) { public static World getWorld(String string) {
if (StringMan.isEqual(string, lastString)) { return Bukkit.getWorld(string);
if (lastWorld != null) {
return lastWorld;
}
}
final World world = Bukkit.getWorld(string);
lastString = string;
lastWorld = world;
return world;
} }
public static String getWorld(final Entity entity) { public static String getWorld(Entity entity) {
return entity.getWorld().getName(); return entity.getWorld().getName();
} }
public static List<Entity> getEntities(final String worldname) { public static List<Entity> getEntities(String worldName) {
return getWorld(worldname).getEntities(); World world = getWorld(worldName);
return world != null ? world.getEntities() : new ArrayList<Entity>();
} }
public static Location getLocation(final Entity entity) { public static Location getLocation(Entity entity) {
final org.bukkit.Location loc = entity.getLocation(); org.bukkit.Location location = entity.getLocation();
final String world = loc.getWorld().getName(); String world = location.getWorld().getName();
return new Location(world, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); return new Location(world, location.getBlockX(), location.getBlockY(), location.getBlockZ());
} }
public static Location getLocationFull(final Entity entity) { public static Location getLocationFull(Entity entity) {
final org.bukkit.Location loc = entity.getLocation(); org.bukkit.Location location = entity.getLocation();
return new Location(loc.getWorld().getName(), MathMan.roundInt(loc.getX()), MathMan.roundInt(loc.getY()), MathMan.roundInt(loc.getZ()), return new Location(location.getWorld().getName(), MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()), MathMan.roundInt(location.getZ()),
loc.getYaw(), loc.getPitch()); location.getYaw(), location.getPitch());
} }
@Override @Override
public boolean isWorld(final String world) { public boolean isWorld(String worldName) {
return getWorld(world) != null; return getWorld(worldName) != null;
} }
@Override @Override
public String getBiome(final String world, final int x, final int z) { public String getBiome(String world, int x, int z) {
return getWorld(world).getBiome(x, z).name(); return getWorld(world).getBiome(x, z).name();
} }
@Override @Override
public void setSign(final String worldname, final int x, final int y, final int z, final String[] lines) { public void setSign(String worldName, int x, int y, int z, String[] lines) {
final World world = getWorld(worldname); World world = getWorld(worldName);
final Block block = world.getBlockAt(x, y, z); Block block = world.getBlockAt(x, y, z);
// block.setType(Material.AIR); // block.setType(Material.AIR);
block.setTypeIdAndData(Material.WALL_SIGN.getId(), (byte) 2, false); block.setTypeIdAndData(Material.WALL_SIGN.getId(), (byte) 2, false);
final BlockState blockstate = block.getState(); BlockState blockstate = block.getState();
if (blockstate instanceof Sign) { if (blockstate instanceof Sign) {
final Sign sign = (Sign) blockstate; final Sign sign = (Sign) blockstate;
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
sign.setLine(i, lines[i]); sign.setLine(i, lines[i]);
} }
sign.update(true); sign.update(true);
TaskManager.runTaskLater(new Runnable() {
@Override
public void run() {
sign.update(true);
}
}, 20);
} }
} }
@Override @Override
public String[] getSign(final Location loc) { public String[] getSign(Location location) {
final Block block = getWorld(loc.getWorld()).getBlockAt(loc.getX(), loc.getY(), loc.getZ()); Block block = getWorld(location.getWorld()).getBlockAt(location.getX(), location.getY(), location.getZ());
if (block != null) { if (block != null) {
if (block.getState() instanceof Sign) { if (block.getState() instanceof Sign) {
final Sign sign = (Sign) block.getState(); Sign sign = (Sign) block.getState();
return sign.getLines(); return sign.getLines();
} }
} }
@ -157,33 +143,70 @@ public class BukkitUtil extends WorldUtil {
} }
@Override @Override
public Location getSpawn(final String world) { public Location getSpawn(PlotPlayer player) {
final org.bukkit.Location temp = getWorld(world).getSpawnLocation(); return getLocation(((BukkitPlayer) player).player.getBedSpawnLocation());
}
@Override
public Location getSpawn(String world) {
org.bukkit.Location temp = getWorld(world).getSpawnLocation();
return new Location(world, temp.getBlockX(), temp.getBlockY(), temp.getBlockZ(), temp.getYaw(), temp.getPitch()); return new Location(world, temp.getBlockX(), temp.getBlockY(), temp.getBlockZ(), temp.getYaw(), temp.getPitch());
} }
@Override @Override
public int getHighestBlock(final String world, final int x, final int z) { public void setSpawn(Location location) {
return getWorld(world).getHighestBlockAt(x, z).getY(); World world = getWorld(location.getWorld());
if (world != null) {
world.setSpawnLocation(location.getX(), location.getY(), location.getZ());
}
} }
@Override @Override
public int getBiomeFromString(final String biomeStr) { public void saveWorld(String worldName) {
try { World world = getWorld(worldName);
final Biome biome = Biome.valueOf(biomeStr.toUpperCase()); if (world != null) {
if (biome == null) { world.save();
return -1;
} }
}
@Override
public int getHighestBlock(String world, int x, int z) {
World bukkitWorld = getWorld(world);
// Skip top and bottom block
for (int y = bukkitWorld.getMaxHeight() - 2; y > 0; y--) {
Block block = bukkitWorld.getBlockAt(x, y, z);
if (block != null) {
Material type = block.getType();
if (type.isSolid()) {
return y + 1;
} else {
switch (type) {
case WATER:
case LAVA:
case STATIONARY_LAVA:
case STATIONARY_WATER:
return y;
}
}
}
}
return bukkitWorld.getMaxHeight();
}
@Override
public int getBiomeFromString(String biomeString) {
try {
Biome biome = Biome.valueOf(biomeString.toUpperCase());
return Arrays.asList(Biome.values()).indexOf(biome); return Arrays.asList(Biome.values()).indexOf(biome);
} catch (final IllegalArgumentException e) { } catch (IllegalArgumentException ignored) {
return -1; return -1;
} }
} }
@Override @Override
public String[] getBiomeList() { public String[] getBiomeList() {
final Biome[] biomes = Biome.values(); Biome[] biomes = Biome.values();
final String[] list = new String[biomes.length]; String[] list = new String[biomes.length];
for (int i = 0; i < biomes.length; i++) { for (int i = 0; i < biomes.length; i++) {
list[i] = biomes[i].name(); list[i] = biomes[i].name();
} }
@ -191,18 +214,18 @@ public class BukkitUtil extends WorldUtil {
} }
@Override @Override
public boolean addItems(final String worldname, final PlotItem items) { public boolean addItems(String worldName, PlotItem items) {
final World world = getWorld(worldname); World world = getWorld(worldName);
final Block block = world.getBlockAt(items.x, items.y, items.z); Block block = world.getBlockAt(items.x, items.y, items.z);
if (block == null) { if (block == null) {
return false; return false;
} }
final BlockState state = block.getState(); BlockState state = block.getState();
if (state instanceof InventoryHolder) { if (state instanceof InventoryHolder) {
final InventoryHolder holder = (InventoryHolder) state; InventoryHolder holder = (InventoryHolder) state;
final Inventory inv = holder.getInventory(); Inventory inv = holder.getInventory();
for (int i = 0; i < items.id.length; i++) { for (int i = 0; i < items.id.length; i++) {
final ItemStack item = new ItemStack(items.id[i], items.amount[i], items.data[i]); ItemStack item = new ItemStack(items.id[i], items.amount[i], items.data[i]);
inv.addItem(item); inv.addItem(item);
} }
state.update(true); state.update(true);
@ -212,11 +235,11 @@ public class BukkitUtil extends WorldUtil {
} }
@Override @Override
public boolean isBlockSolid(final PlotBlock block) { public boolean isBlockSolid(PlotBlock block) {
try { try {
final Material material = Material.getMaterial(block.id); Material material = Material.getMaterial(block.id);
if (material.isBlock() && material.isSolid() && !material.hasGravity()) { if (material.isBlock() && material.isSolid() && !material.hasGravity()) {
final Class<? extends MaterialData> data = material.getData(); Class<? extends MaterialData> data = material.getData();
if (data.equals(MaterialData.class) && !material.isTransparent() && material.isOccluding() if (data.equals(MaterialData.class) && !material.isTransparent() && material.isOccluding()
|| data.equals(Tree.class) || data.equals(Tree.class)
|| data.equals(Sandstone.class) || data.equals(Sandstone.class)
@ -233,16 +256,16 @@ public class BukkitUtil extends WorldUtil {
} }
} }
return false; return false;
} catch (final Exception e) { } catch (Exception ignored) {
return false; return false;
} }
} }
@Override @Override
public String getClosestMatchingName(final PlotBlock block) { public String getClosestMatchingName(PlotBlock block) {
try { try {
return Material.getMaterial(block.id).name(); return Material.getMaterial(block.id).name();
} catch (final Exception e) { } catch (Exception ignored) {
return null; return null;
} }
} }
@ -250,13 +273,12 @@ public class BukkitUtil extends WorldUtil {
@Override @Override
public StringComparison<PlotBlock>.ComparisonResult getClosestBlock(String name) { public StringComparison<PlotBlock>.ComparisonResult getClosestBlock(String name) {
try { try {
final Material material = Material.valueOf(name.toUpperCase()); Material material = Material.valueOf(name.toUpperCase());
return new StringComparison<PlotBlock>().new ComparisonResult(0, new PlotBlock((short) material.getId(), (byte) 0)); return new StringComparison<PlotBlock>().new ComparisonResult(0, PlotBlock.get((short) material.getId(), (byte) 0));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException ignored) {}
}
try { try {
byte data; byte data;
final String[] split = name.split(":"); String[] split = name.split(":");
if (split.length == 2) { if (split.length == 2) {
data = Byte.parseByte(split[1]); data = Byte.parseByte(split[1]);
name = split[0]; name = split[0];
@ -269,23 +291,22 @@ public class BukkitUtil extends WorldUtil {
id = Short.parseShort(split[0]); id = Short.parseShort(split[0]);
match = 0; match = 0;
} else { } else {
final StringComparison<Material>.ComparisonResult comparison = new StringComparison<>(name, Material.values()).getBestMatchAdvanced(); StringComparison<Material>.ComparisonResult comparison = new StringComparison<>(name, Material.values()).getBestMatchAdvanced();
match = comparison.match; match = comparison.match;
id = (short) comparison.best.getId(); id = (short) comparison.best.getId();
} }
final PlotBlock block = new PlotBlock(id, data); PlotBlock block = PlotBlock.get(id, data);
final StringComparison<PlotBlock> outer = new StringComparison<>(); StringComparison<PlotBlock> outer = new StringComparison<>();
return outer.new ComparisonResult(match, block); return outer.new ComparisonResult(match, block);
} catch (NumberFormatException e) { } catch (NumberFormatException ignored) {}
}
return null; return null;
} }
@Override @Override
public void setBiomes(final String worldname, RegionWrapper region, final String biomeStr) { public void setBiomes(String worldName, RegionWrapper region, String biomeString) {
final World world = getWorld(worldname); World world = getWorld(worldName);
final Biome biome = Biome.valueOf(biomeStr.toUpperCase()); Biome biome = Biome.valueOf(biomeString.toUpperCase());
for (int x = region.minX; x <= region.maxX; x++) { for (int x = region.minX; x <= region.maxX; x++) {
for (int z = region.minZ; z <= region.maxZ; z++) { for (int z = region.minZ; z <= region.maxZ; z++) {
world.setBiome(x, z, biome); world.setBiome(x, z, biome);
@ -294,13 +315,13 @@ public class BukkitUtil extends WorldUtil {
} }
@Override @Override
public PlotBlock getBlock(final Location loc) { public PlotBlock getBlock(Location location) {
final World world = getWorld(loc.getWorld()); World world = getWorld(location.getWorld());
final Block block = world.getBlockAt(loc.getX(), loc.getY(), loc.getZ()); Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ());
if (block == null) { if (block == null) {
return new PlotBlock((short) 0, (byte) 0); return PlotBlock.EVERYTHING;
} }
return new PlotBlock((short) block.getTypeId(), block.getData()); return PlotBlock.get((short) block.getTypeId(), block.getData());
} }
@Override @Override

View File

@ -0,0 +1,14 @@
package com.plotsquared.bukkit.util;
public class BukkitVersion {
public static int[] v1_11_0 = {1, 11, 0};
public static int[] v1_10_2 = {1, 10, 2};
public static int[] v1_10_0 = {1, 10, 0};
public static int[] v1_9_4 = {1, 9, 4};
public static int[] v1_9_0 = {1, 9, 0};
public static int[] v1_8_3 = {1, 8, 3};
public static int[] v1_8_0 = {1, 8, 0};
public static int[] v1_7_6 = {1, 7, 6};
public static int[] v1_7_0 = {1, 7, 0};
public static int[] v1_6_0 = {1, 6, 0};
}

View File

@ -0,0 +1,272 @@
package com.plotsquared.bukkit.util;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
public class Metrics {
/** The current revision number. */
private static final int REVISION = 7;
/** The base url of the metrics domain.*/
private static final String BASE_URL = "http://report.mcstats.org";
/** The url used to report a server's status. */
private static final String REPORT_URL = "/plugin/%s";
/** Interval of time to ping (in minutes). */
private static final int PING_INTERVAL = 15;
/** The plugin this metrics submits for. */
private final Plugin plugin;
/** Unique server id. */
private final String guid;
/** The scheduled task. */
private volatile BukkitTask task = null;
public Metrics(Plugin plugin) {
this.plugin = plugin;
this.guid = UUID.randomUUID().toString();
}
/**
* GZip compress a string of bytes.
*
* @param input
*
* @return byte[] the file as a byte array
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (gzos != null) {
try {
gzos.close();
} catch (IOException ignore) {}
}
}
return baos.toByteArray();
}
/**
* Appends a json encoded key/value pair to the given string builder.
*
* @param json
* @param key
* @param value
*
*/
private static void appendJSONPair(StringBuilder json, String key, String value) {
boolean isValueNumeric = false;
try {
if (value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch (NumberFormatException ignored) {
isValueNumeric = false;
}
if (json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJSON(key));
json.append(':');
if (isValueNumeric) {
json.append(value);
} else {
json.append(escapeJSON(value));
}
}
/**
* Escape a string to create a valid JSON string
*
* @param text
*
* @return String
*/
private static String escapeJSON(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for (int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch (chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if (chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
*
* @return the encoded text, as UTF-8
*/
private static String urlEncode(String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
* ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
// Is metrics already running?
if (this.task != null) {
return true;
}
// Begin hitting the server with glorious data
this.task = this.plugin.getServer().getScheduler().runTaskTimerAsynchronously(this.plugin, new Runnable() {
private boolean firstPost = true;
@Override
public void run() {
try {
postPlugin(!this.firstPost);
// After the first post we set firstPost to
// false
// Each post thereafter will be a ping
this.firstPost = false;
} catch (IOException e) {
e.printStackTrace();
}
}
}, 0, PING_INTERVAL * 1200);
return true;
}
/**
* Generic method that posts a plugin to the metrics website.
*/
private void postPlugin(boolean isPing) throws IOException {
// Server software specific section
PluginDescriptionFile description = this.plugin.getDescription();
String pluginName = description.getName();
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = description.getVersion();
String serverVersion = Bukkit.getVersion();
int playersOnline = 0;
try {
if (Bukkit.class.getMethod("getOnlinePlayers", new Class<?>[0]).getReturnType() == Collection.class) {
playersOnline = ((Collection<?>) Bukkit.class.getMethod("getOnlinePlayers", new Class<?>[0]).invoke(null)).size();
} else {
playersOnline = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class<?>[0]).invoke(null)).length;
}
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
ex.printStackTrace();
}
// END server software specific section -- all code below does not use
// any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containing all of the plugin data such as name, version, author, etc
appendJSONPair(json, "guid", this.guid);
appendJSONPair(json, "plugin_version", pluginVersion);
appendJSONPair(json, "server_version", serverVersion);
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJSONPair(json, "osname", osname);
appendJSONPair(json, "osarch", osarch);
appendJSONPair(json, "osversion", osversion);
appendJSONPair(json, "cores", Integer.toString(coreCount));
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
appendJSONPair(json, "ping", "1");
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection = url.openConnection();
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
try {
try (OutputStream os = connection.getOutputStream()) {
os.write(compressed);
os.flush();
}
String response;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
response = reader.readLine();
}
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
if (response == null) {
response = "null";
} else if (response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
}
} catch (IOException ignored) {}
}
}

View File

@ -6,15 +6,9 @@ import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker; import com.google.common.collect.MapMaker;
import com.google.common.io.ByteSink; import com.google.common.io.ByteSink;
import com.google.common.io.ByteSource;
import com.google.common.io.Closeables; import com.google.common.io.Closeables;
import com.google.common.io.Files; import com.google.common.io.InputSupplier;
import com.google.common.primitives.Primitives; import com.google.common.primitives.Primitives;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataInputStream; import java.io.DataInputStream;
@ -25,6 +19,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.AbstractList; import java.util.AbstractList;
@ -39,6 +34,10 @@ import java.util.Set;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
public class NbtFactory { public class NbtFactory {
@ -63,39 +62,43 @@ public class NbtFactory {
// Loading/saving compounds // Loading/saving compounds
private LoadCompoundMethod LOAD_COMPOUND; private LoadCompoundMethod LOAD_COMPOUND;
private Method SAVE_COMPOUND; private Method SAVE_COMPOUND;
/** /**
* Construct an instance of the NBT factory by deducing the class of NBTBase. * Construct an instance of the NBT factory by deducing the class of NBTBase.
*/ */
private NbtFactory() { private NbtFactory() {
if (BASE_CLASS == null) { if (this.BASE_CLASS == null) {
try { try {
// Keep in mind that I do use hard-coded field names - but it's okay as long as we're dealing // Keep in mind that I do use hard-coded field names - but it's okay as long as we're dealing
// with CraftBukkit or its derivatives. This does not work in MCPC+ however. // with CraftBukkit or its derivatives. This does not work in MCPC+ however.
final ClassLoader loader = NbtFactory.class.getClassLoader(); ClassLoader loader = NbtFactory.class.getClassLoader();
final String packageName = getPackageName(); String packageName = getPackageName();
final Class<?> offlinePlayer = loader.loadClass(packageName + ".CraftOfflinePlayer"); Class<?> offlinePlayer = loader.loadClass(packageName + ".CraftOfflinePlayer");
// Prepare NBT // Prepare NBT
COMPOUND_CLASS = getMethod(0, Modifier.STATIC, offlinePlayer, "getData").getReturnType(); this.COMPOUND_CLASS = getMethod(0, Modifier.STATIC, offlinePlayer, "getData").getReturnType();
BASE_CLASS = COMPOUND_CLASS.getSuperclass(); this.BASE_CLASS = this.COMPOUND_CLASS.getSuperclass();
NBT_GET_TYPE = getMethod(0, Modifier.STATIC, BASE_CLASS, "getTypeId"); this.NBT_GET_TYPE = getMethod(0, Modifier.STATIC, this.BASE_CLASS, "getTypeId");
NBT_CREATE_TAG = getMethod(Modifier.STATIC, 0, BASE_CLASS, "createTag", byte.class); this.NBT_CREATE_TAG = getMethod(Modifier.STATIC, 0, this.BASE_CLASS, "createTag", byte.class);
// Prepare CraftItemStack // Prepare CraftItemStack
CRAFT_STACK = loader.loadClass(packageName + ".inventory.CraftItemStack"); this.CRAFT_STACK = loader.loadClass(packageName + ".inventory.CraftItemStack");
CRAFT_HANDLE = getField(null, CRAFT_STACK, "handle"); this.CRAFT_HANDLE = getField(null, this.CRAFT_STACK, "handle");
STACK_TAG = getField(null, CRAFT_HANDLE.getType(), "tag"); this.STACK_TAG = getField(null, this.CRAFT_HANDLE.getType(), "tag");
// Loading/saving // Loading/saving
final String nmsPackage = BASE_CLASS.getPackage().getName(); String nmsPackage = this.BASE_CLASS.getPackage().getName();
initializeNMS(loader, nmsPackage); initializeNMS(loader, nmsPackage);
LOAD_COMPOUND = READ_LIMITER_CLASS != null ? new LoadMethodSkinUpdate(STREAM_TOOLS, READ_LIMITER_CLASS) : if (this.READ_LIMITER_CLASS != null) {
new LoadMethodWorldUpdate(STREAM_TOOLS); this.LOAD_COMPOUND = new LoadMethodSkinUpdate(this.STREAM_TOOLS, this.READ_LIMITER_CLASS);
SAVE_COMPOUND = getMethod(Modifier.STATIC, 0, STREAM_TOOLS, null, BASE_CLASS, DataOutput.class); } else {
this.LOAD_COMPOUND = new LoadMethodWorldUpdate(this.STREAM_TOOLS);
}
this.SAVE_COMPOUND = getMethod(Modifier.STATIC, 0, this.STREAM_TOOLS, null, this.BASE_CLASS, DataOutput.class);
} catch (final ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new IllegalStateException("Unable to find offline player.", e); throw new IllegalStateException("Unable to find offline player.", e);
} }
} }
@ -116,7 +119,7 @@ public class NbtFactory {
* Construct a new NBT list of an unspecified type. * Construct a new NBT list of an unspecified type.
* @return The NBT list. * @return The NBT list.
*/ */
public static NbtList createList(final Object... content) { public static NbtList createList(Object... content) {
return createList(Arrays.asList(content)); return createList(Arrays.asList(content));
} }
@ -124,11 +127,11 @@ public class NbtFactory {
* Construct a new NBT list of an unspecified type. * Construct a new NBT list of an unspecified type.
* @return The NBT list. * @return The NBT list.
*/ */
public static NbtList createList(final Iterable<? extends Object> iterable) { public static NbtList createList(Iterable<? extends Object> iterable) {
final NbtList list = get().new NbtList(INSTANCE.createNbtTag(NbtType.TAG_LIST, null)); NbtList list = get().new NbtList(INSTANCE.createNbtTag(NbtType.TAG_LIST, null));
// Add the content as well // Add the content as well
for (final Object obj : iterable) { for (Object obj : iterable) {
list.add(obj); list.add(obj);
} }
return list; return list;
@ -136,7 +139,6 @@ public class NbtFactory {
/** /**
* Construct a new NBT compound. * Construct a new NBT compound.
* <p>
* *
* @return The NBT compound. * @return The NBT compound.
*/ */
@ -149,29 +151,30 @@ public class NbtFactory {
* @param nmsList - the NBT list. * @param nmsList - the NBT list.
* @return The wrapper. * @return The wrapper.
*/ */
public static NbtList fromList(final Object nmsList) { public static NbtList fromList(Object nmsList) {
return get().new NbtList(nmsList); return get().new NbtList(nmsList);
} }
/** /**
* Load the content of a file from a stream. * Load the content of a file from a stream.
* <p> *
* Use {@link Files#newInputStreamSupplier(java.io.File)} to provide a stream from a file.
* @param stream - the stream supplier. * @param stream - the stream supplier.
* @param option - whether or not to decompress the input stream. * @param option - whether or not to decompress the input stream.
* @return The decoded NBT compound. * @return The decoded NBT compound.
* @throws IOException If anything went wrong. * @throws IOException If anything went wrong.
*/ */
public static NbtCompound fromStream(final ByteSource stream, final StreamOptions option) throws IOException { public static NbtCompound fromStream(InputStream input, StreamOptions option) throws IOException {
InputStream input = null;
DataInputStream data = null; DataInputStream data = null;
boolean suppress = true; boolean suppress = true;
try { try {
input = stream.openStream(); if (option == StreamOptions.GZIP_COMPRESSION) {
data = new DataInputStream(new BufferedInputStream(option == StreamOptions.GZIP_COMPRESSION ? new GZIPInputStream(input) : input)); data = new DataInputStream(new BufferedInputStream(new GZIPInputStream(input)));
} else {
data = new DataInputStream(new BufferedInputStream(input));
}
final NbtCompound result = fromCompound(get().LOAD_COMPOUND.loadNbt(data)); NbtCompound result = fromCompound(get().LOAD_COMPOUND.loadNbt(data));
suppress = false; suppress = false;
return result; return result;
@ -186,14 +189,13 @@ public class NbtFactory {
/** /**
* Save the content of a NBT compound to a stream. * Save the content of a NBT compound to a stream.
* <p> *
* Use {@link Files#newOutputStreamSupplier(java.io.File)} to provide a stream supplier to a file.
* @param source - the NBT compound to save. * @param source - the NBT compound to save.
* @param stream - the stream. * @param stream - the stream.
* @param option - whether or not to compress the output. * @param option - whether or not to compress the output.
* @throws IOException If anything went wrong. * @throws IOException If anything went wrong.
*/ */
public static void saveStream(final NbtCompound source, final ByteSink stream, final StreamOptions option) throws IOException { public static void saveStream(NbtCompound source, ByteSink stream, StreamOptions option) throws IOException {
OutputStream output = null; OutputStream output = null;
DataOutputStream data = null; DataOutputStream data = null;
boolean suppress = true; boolean suppress = true;
@ -216,10 +218,10 @@ public class NbtFactory {
/** /**
* Construct a new NBT wrapper from a compound. * Construct a new NBT wrapper from a compound.
* @param nmsCompound - the NBT compund. * @param nmsCompound - the NBT compound.
* @return The wrapper. * @return The wrapper.
*/ */
public static NbtCompound fromCompound(final Object nmsCompound) { public static NbtCompound fromCompound(Object nmsCompound) {
return get().new NbtCompound(nmsCompound); return get().new NbtCompound(nmsCompound);
} }
@ -230,9 +232,9 @@ public class NbtFactory {
* @param compound - the new NBT compound, or NULL to remove it. * @param compound - the new NBT compound, or NULL to remove it.
* @throws IllegalArgumentException If the stack is not a CraftItemStack, or it represents air. * @throws IllegalArgumentException If the stack is not a CraftItemStack, or it represents air.
*/ */
public static void setItemTag(final ItemStack stack, final NbtCompound compound) { public static void setItemTag(ItemStack stack, NbtCompound compound) {
checkItemStack(stack); checkItemStack(stack);
final Object nms = getFieldValue(get().CRAFT_HANDLE, stack); Object nms = getFieldValue(get().CRAFT_HANDLE, stack);
// Now update the tag compound // Now update the tag compound
setFieldValue(get().STACK_TAG, nms, compound.getHandle()); setFieldValue(get().STACK_TAG, nms, compound.getHandle());
@ -240,21 +242,21 @@ public class NbtFactory {
/** /**
* Construct a wrapper for an NBT tag stored (in memory) in an item stack. This is where * Construct a wrapper for an NBT tag stored (in memory) in an item stack. This is where
* auxillary data such as enchanting, name and lore is stored. It does not include items * auxiliary data such as enchanting, name and lore is stored. It does not include items
* material, damage value or count. * material, damage value or count.
* <p> * <p>
* The item stack must be a wrapper for a CraftItemStack. * The item stack must be a wrapper for a CraftItemStack.
* @param stack - the item stack. * @param stack - the item stack.
* @return A wrapper for its NBT tag. * @return A wrapper for its NBT tag.
*/ */
public static NbtCompound fromItemTag(final ItemStack stack) { public static NbtCompound fromItemTag(ItemStack stack) {
checkItemStack(stack); checkItemStack(stack);
final Object nms = getFieldValue(get().CRAFT_HANDLE, stack); Object nms = getFieldValue(get().CRAFT_HANDLE, stack);
final Object tag = getFieldValue(get().STACK_TAG, nms); Object tag = getFieldValue(get().STACK_TAG, nms);
// Create the tag if it doesn't exist // Create the tag if it doesn't exist
if (tag == null) { if (tag == null) {
final NbtCompound compound = createCompound(); NbtCompound compound = createCompound();
setItemTag(stack, compound); setItemTag(stack, compound);
return compound; return compound;
} }
@ -266,17 +268,17 @@ public class NbtFactory {
* @param stack - the stack to convert. * @param stack - the stack to convert.
* @return The CraftItemStack version. * @return The CraftItemStack version.
*/ */
public static ItemStack getCraftItemStack(final ItemStack stack) { public static ItemStack getCraftItemStack(ItemStack stack) {
// Any need to convert? // Any need to convert?
if ((stack == null) || get().CRAFT_STACK.isAssignableFrom(stack.getClass())) { if ((stack == null) || get().CRAFT_STACK.isAssignableFrom(stack.getClass())) {
return stack; return stack;
} }
try { try {
// Call the private constructor // Call the private constructor
final Constructor<?> caller = INSTANCE.CRAFT_STACK.getDeclaredConstructor(ItemStack.class); Constructor<?> caller = INSTANCE.CRAFT_STACK.getDeclaredConstructor(ItemStack.class);
caller.setAccessible(true); caller.setAccessible(true);
return (ItemStack) caller.newInstance(stack); return (ItemStack) caller.newInstance(stack);
} catch (final Exception e) { } catch (Exception ignored) {
throw new IllegalStateException("Unable to convert " + stack + " + to a CraftItemStack."); throw new IllegalStateException("Unable to convert " + stack + " + to a CraftItemStack.");
} }
} }
@ -285,7 +287,7 @@ public class NbtFactory {
* Ensure that the given stack can store arbitrary NBT information. * Ensure that the given stack can store arbitrary NBT information.
* @param stack - the stack to check. * @param stack - the stack to check.
*/ */
private static void checkItemStack(final ItemStack stack) { private static void checkItemStack(ItemStack stack) {
if (stack == null) { if (stack == null) {
throw new IllegalArgumentException("Stack cannot be NULL."); throw new IllegalArgumentException("Stack cannot be NULL.");
} }
@ -304,32 +306,32 @@ public class NbtFactory {
* @param params - the parameters to supply. * @param params - the parameters to supply.
* @return The result of the method. * @return The result of the method.
*/ */
private static Object invokeMethod(final Method method, final Object target, final Object... params) { private static Object invokeMethod(Method method, Object target, Object... params) {
try { try {
return method.invoke(target, params); return method.invoke(target, params);
} catch (final Exception e) { } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
throw new RuntimeException("Unable to invoke method " + method + " for " + target, e); throw new RuntimeException("Unable to invoke method " + method + " for " + target, e);
} }
} }
private static void setFieldValue(final Field field, final Object target, final Object value) { private static void setFieldValue(Field field, Object target, Object value) {
try { try {
field.set(target, value); field.set(target, value);
} catch (final Exception e) { } catch (IllegalAccessException | IllegalArgumentException e) {
throw new RuntimeException("Unable to set " + field + " for " + target, e); throw new RuntimeException("Unable to set " + field + " for " + target, e);
} }
} }
private static Object getFieldValue(final Field field, final Object target) { private static Object getFieldValue(Field field, Object target) {
try { try {
return field.get(target); return field.get(target);
} catch (final Exception e) { } catch (IllegalAccessException | IllegalArgumentException e) {
throw new RuntimeException("Unable to retrieve " + field + " for " + target, e); throw new RuntimeException("Unable to retrieve " + field + " for " + target, e);
} }
} }
/** /**
* Search for the first publically and privately defined method of the given name and parameter count. * Search for the first publicly and privately defined method of the given name and parameter count.
* @param requireMod - modifiers that are required. * @param requireMod - modifiers that are required.
* @param bannedMod - modifiers that are banned. * @param bannedMod - modifiers that are banned.
* @param clazz - a class to start with. * @param clazz - a class to start with.
@ -338,9 +340,9 @@ public class NbtFactory {
* @return The first method by this name. * @return The first method by this name.
* @throws IllegalStateException If we cannot find this method. * @throws IllegalStateException If we cannot find this method.
*/ */
private static Method getMethod(final int requireMod, final int bannedMod, final Class<?> clazz, final String methodName, private static Method getMethod(int requireMod, int bannedMod, Class<?> clazz, String methodName,
final Class<?>... params) { Class<?>... params) {
for (final Method method : clazz.getDeclaredMethods()) { for (Method method : clazz.getDeclaredMethods()) {
// Limitation: Doesn't handle overloads // Limitation: Doesn't handle overloads
if (((method.getModifiers() & requireMod) == requireMod) if (((method.getModifiers() & requireMod) == requireMod)
&& ((method.getModifiers() & bannedMod) == 0) && ((method.getModifiers() & bannedMod) == 0)
@ -359,19 +361,19 @@ public class NbtFactory {
} }
/** /**
* Search for the first publically and privately defined field of the given name. * Search for the first publicly and privately defined field of the given name.
* @param instance - an instance of the class with the field. * @param instance - an instance of the class with the field.
* @param clazz - an optional class to start with, or NULL to deduce it from instance. * @param clazz - an optional class to start with, or NULL to deduce it from instance.
* @param fieldName - the field name. * @param fieldName - the field name.
* @return The first field by this name. * @return The first field by this name.
* @throws IllegalStateException If we cannot find this field. * @throws IllegalStateException If we cannot find this field.
*/ */
private static Field getField(final Object instance, Class<?> clazz, final String fieldName) { private static Field getField(Object instance, Class<?> clazz, String fieldName) {
if (clazz == null) { if (clazz == null) {
clazz = instance.getClass(); clazz = instance.getClass();
} }
// Ignore access rules // Ignore access rules
for (final Field field : clazz.getDeclaredFields()) { for (Field field : clazz.getDeclaredFields()) {
if (field.getName().equals(fieldName)) { if (field.getName().equals(fieldName)) {
field.setAccessible(true); field.setAccessible(true);
return field; return field;
@ -384,18 +386,16 @@ public class NbtFactory {
throw new IllegalStateException("Unable to find field " + fieldName + " in " + instance); throw new IllegalStateException("Unable to find field " + fieldName + " in " + instance);
} }
private void initializeNMS(final ClassLoader loader, final String nmsPackage) { private void initializeNMS(ClassLoader loader, String nmsPackage) {
try { try {
STREAM_TOOLS = loader.loadClass(nmsPackage + ".NBTCompressedStreamTools"); this.STREAM_TOOLS = loader.loadClass(nmsPackage + ".NBTCompressedStreamTools");
READ_LIMITER_CLASS = loader.loadClass(nmsPackage + ".NBTReadLimiter"); this.READ_LIMITER_CLASS = loader.loadClass(nmsPackage + ".NBTReadLimiter");
} catch (final ClassNotFoundException e) { } catch (ClassNotFoundException ignored) {}
// Ignore - we will detect this later
}
} }
private String getPackageName() { private String getPackageName() {
final Server server = Bukkit.getServer(); Server server = Bukkit.getServer();
final String name = server != null ? server.getClass().getPackage().getName() : null; String name = server != null ? server.getClass().getPackage().getName() : null;
if ((name != null) && name.contains("craftbukkit")) { if ((name != null) && name.contains("craftbukkit")) {
return name; return name;
@ -406,12 +406,12 @@ public class NbtFactory {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Map<String, Object> getDataMap(final Object handle) { private Map<String, Object> getDataMap(Object handle) {
return (Map<String, Object>) getFieldValue(getDataField(NbtType.TAG_COMPOUND, handle), handle); return (Map<String, Object>) getFieldValue(getDataField(NbtType.TAG_COMPOUND, handle), handle);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private List<Object> getDataList(final Object handle) { private List<Object> getDataList(Object handle) {
return (List<Object>) getFieldValue(getDataField(NbtType.TAG_LIST, handle), handle); return (List<Object>) getFieldValue(getDataField(NbtType.TAG_LIST, handle), handle);
} }
@ -420,19 +420,17 @@ public class NbtFactory {
* @param value - the value of the element to create. Can be a List or a Map. * @param value - the value of the element to create. Can be a List or a Map.
* @return The NBT element. * @return The NBT element.
*/ */
private Object unwrapValue(final Object value) { private Object unwrapValue(Object value) {
if (value == null) { if (value == null) {
return null; return null;
} }
if (value instanceof Wrapper) { if (value instanceof Wrapper) {
return ((Wrapper) value).getHandle(); return ((Wrapper) value).getHandle();
} else if (value instanceof List) { } else if (value instanceof List) {
throw new IllegalArgumentException("Can only insert a WrappedList."); throw new IllegalArgumentException("Can only insert a WrappedList.");
} else if (value instanceof Map) { } else if (value instanceof Map) {
throw new IllegalArgumentException("Can only insert a WrappedCompound."); throw new IllegalArgumentException("Can only insert a WrappedCompound.");
} else { } else {
return createNbtTag(getPrimitiveType(value), value); return createNbtTag(getPrimitiveType(value), value);
} }
@ -440,18 +438,17 @@ public class NbtFactory {
/** /**
* Convert a given NBT element to a primitive wrapper or List/Map equivalent. * Convert a given NBT element to a primitive wrapper or List/Map equivalent.
* <p> * <p> All changes to any mutable objects will be reflected in the underlying NBT element(s).
* All changes to any mutable objects will be reflected in the underlying NBT element(s).
* @param nms - the NBT element. * @param nms - the NBT element.
* @return The wrapper equivalent. * @return The wrapper equivalent.
*/ */
private Object wrapNative(final Object nms) { private Object wrapNative(Object nms) {
if (nms == null) { if (nms == null) {
return null; return null;
} }
if (BASE_CLASS.isAssignableFrom(nms.getClass())) { if (this.BASE_CLASS.isAssignableFrom(nms.getClass())) {
final NbtType type = getNbtType(nms); NbtType type = getNbtType(nms);
// Handle the different types // Handle the different types
switch (type) { switch (type) {
@ -472,8 +469,8 @@ public class NbtFactory {
* @param value - the value, or NULL to keep the original value. * @param value - the value, or NULL to keep the original value.
* @return The created tag. * @return The created tag.
*/ */
private Object createNbtTag(final NbtType type, final Object value) { private Object createNbtTag(NbtType type, Object value) {
final Object tag = invokeMethod(NBT_CREATE_TAG, null, (byte) type.id); Object tag = invokeMethod(this.NBT_CREATE_TAG, null, (byte) type.id);
if (value != null) { if (value != null) {
setFieldValue(getDataField(type, tag), tag, value); setFieldValue(getDataField(type, tag), tag, value);
@ -487,11 +484,11 @@ public class NbtFactory {
* @param nms - the NBT class instance. * @param nms - the NBT class instance.
* @return The corresponding field. * @return The corresponding field.
*/ */
private Field getDataField(final NbtType type, final Object nms) { private Field getDataField(NbtType type, Object nms) {
if (DATA_FIELD[type.id] == null) { if (this.DATA_FIELD[type.id] == null) {
DATA_FIELD[type.id] = getField(nms, null, type.getFieldName()); this.DATA_FIELD[type.id] = getField(nms, null, type.getFieldName());
} }
return DATA_FIELD[type.id]; return this.DATA_FIELD[type.id];
} }
/** /**
@ -499,8 +496,8 @@ public class NbtFactory {
* @param nms - the native NBT tag. * @param nms - the native NBT tag.
* @return The corresponding type. * @return The corresponding type.
*/ */
private NbtType getNbtType(final Object nms) { private NbtType getNbtType(Object nms) {
final int type = (Byte) invokeMethod(NBT_GET_TYPE, nms); int type = (Byte) invokeMethod(this.NBT_GET_TYPE, nms);
return NBT_ENUM.get(type); return NBT_ENUM.get(type);
} }
@ -509,8 +506,8 @@ public class NbtFactory {
* @param primitive - the primitive type. * @param primitive - the primitive type.
* @return The corresponding type. * @return The corresponding type.
*/ */
private NbtType getPrimitiveType(final Object primitive) { private NbtType getPrimitiveType(Object primitive) {
final NbtType type = NBT_ENUM.get(NBT_CLASS.inverse().get(Primitives.unwrap(primitive.getClass()))); NbtType type = NBT_ENUM.get(NBT_CLASS.inverse().get(Primitives.unwrap(primitive.getClass())));
// Display the illegal value at least // Display the illegal value at least
if (type == null) { if (type == null) {
@ -544,7 +541,7 @@ public class NbtFactory {
// Unique NBT type // Unique NBT type
public final int id; public final int id;
NbtType(final int id, final Class<?> type) { NbtType(int id, Class<?> type) {
this.id = id; this.id = id;
NBT_CLASS.put(id, type); NBT_CLASS.put(id, type);
NBT_ENUM.put(id, this); NBT_ENUM.put(id, this);
@ -582,9 +579,9 @@ public class NbtFactory {
protected Method staticMethod; protected Method staticMethod;
protected void setMethod(final Method method) { protected void setMethod(Method method) {
staticMethod = method; this.staticMethod = method;
staticMethod.setAccessible(true); this.staticMethod.setAccessible(true);
} }
/** /**
@ -592,7 +589,7 @@ public class NbtFactory {
* @param input - the input stream. * @param input - the input stream.
* @return The loaded NBT compound. * @return The loaded NBT compound.
*/ */
public abstract Object loadNbt(final DataInput input); public abstract Object loadNbt(DataInput input);
} }
/** /**
@ -600,13 +597,13 @@ public class NbtFactory {
*/ */
private static class LoadMethodWorldUpdate extends LoadCompoundMethod { private static class LoadMethodWorldUpdate extends LoadCompoundMethod {
public LoadMethodWorldUpdate(final Class<?> streamClass) { LoadMethodWorldUpdate(Class<?> streamClass) {
setMethod(getMethod(Modifier.STATIC, 0, streamClass, null, DataInput.class)); setMethod(getMethod(Modifier.STATIC, 0, streamClass, null, DataInput.class));
} }
@Override @Override
public Object loadNbt(final DataInput input) { public Object loadNbt(DataInput input) {
return invokeMethod(staticMethod, null, input); return invokeMethod(this.staticMethod, null, input);
} }
} }
@ -617,15 +614,15 @@ public class NbtFactory {
private Object readLimiter; private Object readLimiter;
public LoadMethodSkinUpdate(final Class<?> streamClass, final Class<?> readLimiterClass) { LoadMethodSkinUpdate(Class<?> streamClass, Class<?> readLimiterClass) {
setMethod(getMethod(Modifier.STATIC, 0, streamClass, null, DataInput.class, readLimiterClass)); setMethod(getMethod(Modifier.STATIC, 0, streamClass, null, DataInput.class, readLimiterClass));
// Find the unlimited read limiter // Find the unlimited read limiter
for (final Field field : readLimiterClass.getDeclaredFields()) { for (Field field : readLimiterClass.getDeclaredFields()) {
if (readLimiterClass.isAssignableFrom(field.getType())) { if (readLimiterClass.isAssignableFrom(field.getType())) {
try { try {
readLimiter = field.get(null); this.readLimiter = field.get(null);
} catch (final Exception e) { } catch (Exception e) {
throw new RuntimeException("Cannot retrieve read limiter.", e); throw new RuntimeException("Cannot retrieve read limiter.", e);
} }
} }
@ -633,18 +630,17 @@ public class NbtFactory {
} }
@Override @Override
public Object loadNbt(final DataInput input) { public Object loadNbt(DataInput input) {
return invokeMethod(staticMethod, null, input, readLimiter); return invokeMethod(this.staticMethod, null, input, this.readLimiter);
} }
} }
/** /**
* Represents a root NBT compound. * Represents a root NBT compound.
* <p> * <p> All changes to this map will be reflected in the underlying NBT compound. Values may only be one of the following:
* All changes to this map will be reflected in the underlying NBT compound. Values may only be one of the following:
* <ul> * <ul>
* <li>Primitive types</li> * <li>Primitive types</li>
* <li>{@link java.lang.String String}</li> * <li>{@link String String}</li>
* <li>{@link NbtList}</li> * <li>{@link NbtList}</li>
* <li>{@link NbtCompound}</li> * <li>{@link NbtCompound}</li>
* </ul> * </ul>
@ -658,44 +654,44 @@ public class NbtFactory {
*/ */
public final class NbtCompound extends ConvertedMap { public final class NbtCompound extends ConvertedMap {
private NbtCompound(final Object handle) { private NbtCompound(Object handle) {
super(handle, getDataMap(handle)); super(handle, getDataMap(handle));
} }
// Simplifiying access to each value // Simplifying access to each value
public Byte getByte(final String key, final Byte defaultValue) { public Byte getByte(String key, Byte defaultValue) {
return containsKey(key) ? (Byte) get(key) : defaultValue; return containsKey(key) ? (Byte) get(key) : defaultValue;
} }
public Short getShort(final String key, final Short defaultValue) { public Short getShort(String key, Short defaultValue) {
return containsKey(key) ? (Short) get(key) : defaultValue; return containsKey(key) ? (Short) get(key) : defaultValue;
} }
public Integer getInteger(final String key, final Integer defaultValue) { public Integer getInteger(String key, Integer defaultValue) {
return containsKey(key) ? (Integer) get(key) : defaultValue; return containsKey(key) ? (Integer) get(key) : defaultValue;
} }
public Long getLong(final String key, final Long defaultValue) { public Long getLong(String key, Long defaultValue) {
return containsKey(key) ? (Long) get(key) : defaultValue; return containsKey(key) ? (Long) get(key) : defaultValue;
} }
public Float getFloat(final String key, final Float defaultValue) { public Float getFloat(String key, Float defaultValue) {
return containsKey(key) ? (Float) get(key) : defaultValue; return containsKey(key) ? (Float) get(key) : defaultValue;
} }
public Double getDouble(final String key, final Double defaultValue) { public Double getDouble(String key, Double defaultValue) {
return containsKey(key) ? (Double) get(key) : defaultValue; return containsKey(key) ? (Double) get(key) : defaultValue;
} }
public String getString(final String key, final String defaultValue) { public String getString(String key, String defaultValue) {
return containsKey(key) ? (String) get(key) : defaultValue; return containsKey(key) ? (String) get(key) : defaultValue;
} }
public byte[] getByteArray(final String key, final byte[] defaultValue) { public byte[] getByteArray(String key, byte[] defaultValue) {
return containsKey(key) ? (byte[]) get(key) : defaultValue; return containsKey(key) ? (byte[]) get(key) : defaultValue;
} }
public int[] getIntegerArray(final String key, final int[] defaultValue) { public int[] getIntegerArray(String key, int[] defaultValue) {
return containsKey(key) ? (int[]) get(key) : defaultValue; return containsKey(key) ? (int[]) get(key) : defaultValue;
} }
@ -705,7 +701,7 @@ public class NbtFactory {
* @param createNew - whether or not to create a new list if its missing. * @param createNew - whether or not to create a new list if its missing.
* @return An existing list, a new list or NULL. * @return An existing list, a new list or NULL.
*/ */
public NbtList getList(final String key, final boolean createNew) { public NbtList getList(String key, boolean createNew) {
NbtList list = (NbtList) get(key); NbtList list = (NbtList) get(key);
if ((list == null) && createNew) { if ((list == null) && createNew) {
@ -720,7 +716,7 @@ public class NbtFactory {
* @param createNew - whether or not to create a new map if its missing. * @param createNew - whether or not to create a new map if its missing.
* @return An existing map, a new map or NULL. * @return An existing map, a new map or NULL.
*/ */
public NbtCompound getMap(final String key, final boolean createNew) { public NbtCompound getMap(String key, boolean createNew) {
return getMap(Collections.singletonList(key), createNew); return getMap(Collections.singletonList(key), createNew);
} }
@ -735,9 +731,9 @@ public class NbtFactory {
* @param value - the new value of this entry. * @param value - the new value of this entry.
* @return This compound, for chaining. * @return This compound, for chaining.
*/ */
public NbtCompound putPath(final String path, final Object value) { public NbtCompound putPath(String path, Object value) {
final List<String> entries = getPathElements(path); List<String> entries = getPathElements(path);
final Map<String, Object> map = getMap(entries.subList(0, entries.size() - 1), true); Map<String, Object> map = getMap(entries.subList(0, entries.size() - 1), true);
map.put(entries.get(entries.size() - 1), value); map.put(entries.get(entries.size() - 1), value);
return this; return this;
@ -752,9 +748,9 @@ public class NbtFactory {
* @return The value, or NULL if not found. * @return The value, or NULL if not found.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T getPath(final String path) { public <T> T getPath(String path) {
final List<String> entries = getPathElements(path); List<String> entries = getPathElements(path);
final NbtCompound map = getMap(entries.subList(0, entries.size() - 1), false); NbtCompound map = getMap(entries.subList(0, entries.size() - 1), false);
if (map != null) { if (map != null) {
return (T) map.get(entries.get(entries.size() - 1)); return (T) map.get(entries.get(entries.size() - 1));
@ -764,13 +760,11 @@ public class NbtFactory {
/** /**
* Save the content of a NBT compound to a stream. * Save the content of a NBT compound to a stream.
* <p>
* Use {@link Files#newOutputStreamSupplier(java.io.File)} to provide a stream supplier to a file.
* @param stream - the output stream. * @param stream - the output stream.
* @param option - whether or not to compress the output. * @param option - whether or not to compress the output.
* @throws IOException If anything went wrong. * @throws IOException If anything went wrong.
*/ */
public void saveTo(final ByteSink stream, final StreamOptions option) throws IOException { public void saveTo(ByteSink stream, StreamOptions option) throws IOException {
saveStream(this, stream, option); saveStream(this, stream, option);
} }
@ -780,10 +774,10 @@ public class NbtFactory {
* @param createNew - whether or not to create new compounds on the way. * @param createNew - whether or not to create new compounds on the way.
* @return The map at this location. * @return The map at this location.
*/ */
private NbtCompound getMap(final Iterable<String> path, final boolean createNew) { private NbtCompound getMap(Iterable<String> path, boolean createNew) {
NbtCompound current = this; NbtCompound current = this;
for (final String entry : path) { for (String entry : path) {
NbtCompound child = (NbtCompound) current.get(entry); NbtCompound child = (NbtCompound) current.get(entry);
if (child == null) { if (child == null) {
@ -802,7 +796,7 @@ public class NbtFactory {
* @param path - the path to split. * @param path - the path to split.
* @return The elements. * @return The elements.
*/ */
private List<String> getPathElements(final String path) { private List<String> getPathElements(String path) {
return Lists.newArrayList(Splitter.on(".").omitEmptyStrings().split(path)); return Lists.newArrayList(Splitter.on(".").omitEmptyStrings().split(path));
} }
} }
@ -818,7 +812,7 @@ public class NbtFactory {
*/ */
public final class NbtList extends ConvertedList { public final class NbtList extends ConvertedList {
private NbtList(final Object handle) { private NbtList(Object handle) {
super(handle, getDataList(handle)); super(handle, getDataList(handle));
} }
} }
@ -832,15 +826,15 @@ public class NbtFactory {
// Don't recreate wrapper objects // Don't recreate wrapper objects
private final ConcurrentMap<Object, Object> cache = new MapMaker().weakKeys().makeMap(); private final ConcurrentMap<Object, Object> cache = new MapMaker().weakKeys().makeMap();
public Object wrap(final Object value) { public Object wrap(Object value) {
Object current = cache.get(value); Object current = this.cache.get(value);
if (current == null) { if (current == null) {
current = wrapNative(value); current = wrapNative(value);
// Only cache composite objects // Only cache composite objects
if ((current instanceof ConvertedMap) || (current instanceof ConvertedList)) { if ((current instanceof ConvertedMap) || (current instanceof ConvertedList)) {
cache.put(value, current); this.cache.put(value, current);
} }
} }
return current; return current;
@ -859,57 +853,57 @@ public class NbtFactory {
private final CachedNativeWrapper cache = new CachedNativeWrapper(); private final CachedNativeWrapper cache = new CachedNativeWrapper();
public ConvertedMap(final Object handle, final Map<String, Object> original) { public ConvertedMap(Object handle, Map<String, Object> original) {
this.handle = handle; this.handle = handle;
this.original = original; this.original = original;
} }
// For converting back and forth // For converting back and forth
protected Object wrapOutgoing(final Object value) { protected Object wrapOutgoing(Object value) {
return cache.wrap(value); return this.cache.wrap(value);
} }
protected Object unwrapIncoming(final Object wrapped) { protected Object unwrapIncoming(Object wrapped) {
return unwrapValue(wrapped); return unwrapValue(wrapped);
} }
// Modification // Modification
@Override @Override
public Object put(final String key, final Object value) { public Object put(String key, Object value) {
return wrapOutgoing(original.put(key, unwrapIncoming(value))); return wrapOutgoing(this.original.put(key, unwrapIncoming(value)));
} }
// Performance // Performance
@Override @Override
public Object get(final Object key) { public Object get(Object key) {
return wrapOutgoing(original.get(key)); return wrapOutgoing(this.original.get(key));
} }
@Override @Override
public Object remove(final Object key) { public Object remove(Object key) {
return wrapOutgoing(original.remove(key)); return wrapOutgoing(this.original.remove(key));
} }
@Override @Override
public boolean containsKey(final Object key) { public boolean containsKey(Object key) {
return original.containsKey(key); return this.original.containsKey(key);
} }
@Override @Override
public Set<Entry<String, Object>> entrySet() { public Set<Entry<String, Object>> entrySet() {
return new AbstractSet<Entry<String, Object>>() { return new AbstractSet<Entry<String, Object>>() {
@Override @Override
public boolean add(final Entry<String, Object> e) { public boolean add(Entry<String, Object> e) {
final String key = e.getKey(); String key = e.getKey();
final Object value = e.getValue(); Object value = e.getValue();
original.put(key, unwrapIncoming(value)); ConvertedMap.this.original.put(key, unwrapIncoming(value));
return true; return true;
} }
@Override @Override
public int size() { public int size() {
return original.size(); return ConvertedMap.this.original.size();
} }
@Override @Override
@ -920,7 +914,7 @@ public class NbtFactory {
} }
private Iterator<Entry<String, Object>> iterator() { private Iterator<Entry<String, Object>> iterator() {
final Iterator<Entry<String, Object>> proxy = original.entrySet().iterator(); final Iterator<Entry<String, Object>> proxy = this.original.entrySet().iterator();
return new Iterator<Entry<String, Object>>() { return new Iterator<Entry<String, Object>>() {
@Override @Override
@ -930,7 +924,7 @@ public class NbtFactory {
@Override @Override
public Entry<String, Object> next() { public Entry<String, Object> next() {
final Entry<String, Object> entry = proxy.next(); Entry<String, Object> entry = proxy.next();
return new SimpleEntry<String, Object>(entry.getKey(), wrapOutgoing(entry.getValue())); return new SimpleEntry<String, Object>(entry.getKey(), wrapOutgoing(entry.getValue()));
} }
@ -944,7 +938,7 @@ public class NbtFactory {
@Override @Override
public Object getHandle() { public Object getHandle() {
return handle; return this.handle;
} }
} }
@ -960,61 +954,61 @@ public class NbtFactory {
private final List<Object> original; private final List<Object> original;
private final CachedNativeWrapper cache = new CachedNativeWrapper(); private final CachedNativeWrapper cache = new CachedNativeWrapper();
public ConvertedList(final Object handle, final List<Object> original) { public ConvertedList(Object handle, List<Object> original) {
if (NBT_LIST_TYPE == null) { if (NbtFactory.this.NBT_LIST_TYPE == null) {
NBT_LIST_TYPE = getField(handle, null, "type"); NbtFactory.this.NBT_LIST_TYPE = getField(handle, null, "type");
} }
this.handle = handle; this.handle = handle;
this.original = original; this.original = original;
} }
protected Object wrapOutgoing(final Object value) { protected Object wrapOutgoing(Object value) {
return cache.wrap(value); return this.cache.wrap(value);
} }
protected Object unwrapIncoming(final Object wrapped) { protected Object unwrapIncoming(Object wrapped) {
return unwrapValue(wrapped); return unwrapValue(wrapped);
} }
@Override @Override
public Object get(final int index) { public Object get(int index) {
return wrapOutgoing(original.get(index)); return wrapOutgoing(this.original.get(index));
} }
@Override @Override
public int size() { public int size() {
return original.size(); return this.original.size();
} }
@Override @Override
public Object set(final int index, final Object element) { public Object set(int index, Object element) {
return wrapOutgoing(original.set(index, unwrapIncoming(element))); return wrapOutgoing(this.original.set(index, unwrapIncoming(element)));
} }
@Override @Override
public void add(final int index, final Object element) { public void add(int index, Object element) {
final Object nbt = unwrapIncoming(element); Object nbt = unwrapIncoming(element);
// Set the list type if its the first element // Set the list type if its the first element
if (size() == 0) { if (size() == 0) {
setFieldValue(NBT_LIST_TYPE, handle, (byte) getNbtType(nbt).id); setFieldValue(NbtFactory.this.NBT_LIST_TYPE, this.handle, (byte) getNbtType(nbt).id);
} }
original.add(index, nbt); this.original.add(index, nbt);
} }
@Override @Override
public Object remove(final int index) { public Object remove(int index) {
return wrapOutgoing(original.remove(index)); return wrapOutgoing(this.original.remove(index));
} }
@Override @Override
public boolean remove(final Object o) { public boolean remove(Object o) {
return original.remove(unwrapIncoming(o)); return this.original.remove(unwrapIncoming(o));
} }
@Override @Override
public Object getHandle() { public Object getHandle() {
return handle; return this.handle;
} }
} }
} }

View File

@ -19,15 +19,15 @@ import java.util.UUID;
public class OfflinePlayerUtil { public class OfflinePlayerUtil {
public static Player loadPlayer(final String name) { public static Player loadPlayer(String name) {
return loadPlayer(Bukkit.getOfflinePlayer(name)); return loadPlayer(Bukkit.getOfflinePlayer(name));
} }
public static Player loadPlayer(final UUID id) { public static Player loadPlayer(UUID id) {
return loadPlayer(Bukkit.getOfflinePlayer(id)); return loadPlayer(Bukkit.getOfflinePlayer(id));
} }
public static Player loadPlayer(final OfflinePlayer player) { public static Player loadPlayer(OfflinePlayer player) {
if (player == null) { if (player == null) {
return null; return null;
} }
@ -37,26 +37,26 @@ public class OfflinePlayerUtil {
return loadPlayer(player.getUniqueId(), player.getName()); return loadPlayer(player.getUniqueId(), player.getName());
} }
private static Player loadPlayer(final UUID id, final String name) { private static Player loadPlayer(UUID id, String name) {
final Object server = getMinecraftServer(); Object server = getMinecraftServer();
final Object interactManager = newPlayerInteractManager(); Object interactManager = newPlayerInteractManager();
final Object worldServer = getWorldServer(); Object worldServer = getWorldServer();
final Object profile = newGameProfile(id, name); Object profile = newGameProfile(id, name);
final Class<?> entityPlayerClass = getNmsClass("EntityPlayer"); Class<?> entityPlayerClass = getNmsClass("EntityPlayer");
final Constructor entityPlayerConstructor = makeConstructor(entityPlayerClass, getNmsClass("MinecraftServer"), getNmsClass("WorldServer"), Constructor entityPlayerConstructor = makeConstructor(entityPlayerClass, getNmsClass("MinecraftServer"), getNmsClass("WorldServer"),
getUtilClass("com.mojang.authlib.GameProfile"), getUtilClass("com.mojang.authlib.GameProfile"),
getNmsClass("PlayerInteractManager")); getNmsClass("PlayerInteractManager"));
final Object entityPlayer = callConstructor(entityPlayerConstructor, server, worldServer, profile, interactManager); Object entityPlayer = callConstructor(entityPlayerConstructor, server, worldServer, profile, interactManager);
return (Player) getBukkitEntity(entityPlayer); return (Player) getBukkitEntity(entityPlayer);
} }
private static Object newGameProfile(final UUID id, final String name) { private static Object newGameProfile(UUID id, String name) {
final Class<?> gameProfileClass = getUtilClass("com.mojang.authlib.GameProfile"); Class<?> gameProfileClass = getUtilClass("com.mojang.authlib.GameProfile");
if (gameProfileClass == null) { //Before uuids if (gameProfileClass == null) { //Before uuids
return name; return name;
} }
Constructor gameProfileConstructor = makeConstructor(gameProfileClass, UUID.class, String.class); Constructor gameProfileConstructor = makeConstructor(gameProfileClass, UUID.class, String.class);
if (gameProfileConstructor == null) { //Verson has string constructor if (gameProfileConstructor == null) { //Version has string constructor
gameProfileConstructor = makeConstructor(gameProfileClass, String.class, String.class); gameProfileConstructor = makeConstructor(gameProfileClass, String.class, String.class);
return callConstructor(gameProfileConstructor, id.toString(), name); return callConstructor(gameProfileConstructor, id.toString(), name);
} else { //Version has uuid constructor } else { //Version has uuid constructor
@ -65,17 +65,17 @@ public class OfflinePlayerUtil {
} }
private static Object newPlayerInteractManager() { private static Object newPlayerInteractManager() {
final Object worldServer = getWorldServer(); Object worldServer = getWorldServer();
final Class<?> playerInteractClass = getNmsClass("PlayerInteractManager"); Class<?> playerInteractClass = getNmsClass("PlayerInteractManager");
final Class<?> worldClass = getNmsClass("World"); Class<?> worldClass = getNmsClass("World");
final Constructor c = makeConstructor(playerInteractClass, worldClass); Constructor c = makeConstructor(playerInteractClass, worldClass);
return callConstructor(c, worldServer); return callConstructor(c, worldServer);
} }
private static Object getWorldServer() { private static Object getWorldServer() {
final Object server = getMinecraftServer(); Object server = getMinecraftServer();
final Class<?> minecraftServerClass = getNmsClass("MinecraftServer"); Class<?> minecraftServerClass = getNmsClass("MinecraftServer");
final Method getWorldServer = makeMethod(minecraftServerClass, "getWorldServer", int.class); Method getWorldServer = makeMethod(minecraftServerClass, "getWorldServer", int.class);
return callMethod(getWorldServer, server, 0); return callMethod(getWorldServer, server, 0);
} }
@ -85,8 +85,8 @@ public class OfflinePlayerUtil {
return callMethod(makeMethod(getCbClass("CraftServer"), "getServer"), Bukkit.getServer()); return callMethod(makeMethod(getCbClass("CraftServer"), "getServer"), Bukkit.getServer());
} }
private static Entity getBukkitEntity(final Object o) { private static Entity getBukkitEntity(Object o) {
final Method getBukkitEntity = makeMethod(o.getClass(), "getBukkitEntity"); Method getBukkitEntity = makeMethod(o.getClass(), "getBukkitEntity");
return callMethod(getBukkitEntity, o); return callMethod(getBukkitEntity, o);
} }
} }

View File

@ -0,0 +1,168 @@
package com.plotsquared.bukkit.util;
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.object.ChunkLoc;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefConstructor;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefField;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.UUIDHandler;
import com.plotsquared.bukkit.object.BukkitPlayer;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
/**
* An utility that can be used to send chunks, rather than using bukkit code
* to do so (uses heavy NMS).
*/
public class SendChunk {
private final RefMethod methodGetHandlePlayer;
private final RefMethod methodGetHandleChunk;
private final RefConstructor mapChunk;
private final RefField connection;
private final RefMethod send;
private final RefMethod methodInitLighting;
/**
* Constructor.
*/
public SendChunk() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
RefConstructor tempMapChunk;
RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer");
this.methodGetHandlePlayer = classCraftPlayer.getMethod("getHandle");
RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
RefClass classChunk = getRefClass("{nms}.Chunk");
this.methodInitLighting = classChunk.getMethod("initLighting");
RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk");
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_4)) {
//this works for 1.9.4 and 1.10
tempMapChunk = classMapChunk.getConstructor(classChunk.getRealClass(),int.class);
} else {
try {
tempMapChunk = classMapChunk.getConstructor(classChunk.getRealClass(), boolean.class, int.class);
} catch (NoSuchMethodException ignored) {
tempMapChunk = classMapChunk.getConstructor(classChunk.getRealClass(),boolean.class, int.class, int.class);
}
}
this.mapChunk = tempMapChunk;
RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer");
this.connection = classEntityPlayer.getField("playerConnection");
RefClass classPacket = getRefClass("{nms}.Packet");
RefClass classConnection = getRefClass("{nms}.PlayerConnection");
this.send = classConnection.getMethod("sendPacket", classPacket.getRealClass());
}
public void sendChunk(Collection<Chunk> input) {
HashSet<Chunk> chunks = new HashSet<>(input);
HashMap<String, ArrayList<Chunk>> map = new HashMap<>();
int view = Bukkit.getServer().getViewDistance();
for (Chunk chunk : chunks) {
String world = chunk.getWorld().getName();
ArrayList<Chunk> list = map.get(world);
if (list == null) {
list = new ArrayList<>();
map.put(world, list);
}
list.add(chunk);
Object c = this.methodGetHandleChunk.of(chunk).call();
this.methodInitLighting.of(c).call();
}
for (Entry<String, PlotPlayer> entry : UUIDHandler.getPlayers().entrySet()) {
PlotPlayer pp = entry.getValue();
Plot plot = pp.getCurrentPlot();
Location location = null;
String world;
if (plot != null) {
world = plot.getWorldName();
} else {
location = pp.getLocation();
world = location.getWorld();
}
ArrayList<Chunk> list = map.get(world);
if (list == null) {
continue;
}
if (location == null) {
location = pp.getLocation();
}
int cx = location.getX() >> 4;
int cz = location.getZ() >> 4;
Player player = ((BukkitPlayer) pp).player;
Object entity = this.methodGetHandlePlayer.of(player).call();
for (Chunk chunk : list) {
int dx = Math.abs(cx - chunk.getX());
int dz = Math.abs(cz - chunk.getZ());
if ((dx > view) || (dz > view)) {
continue;
}
Object c = this.methodGetHandleChunk.of(chunk).call();
chunks.remove(chunk);
Object con = this.connection.of(entity).get();
Object packet = null;
if (PS.get().checkVersion(PS.get().IMP.getServerVersion(), BukkitVersion.v1_9_4)) {
try {
packet = this.mapChunk.create(c,65535);
} catch (Exception ignored) {}
} else {
try {
packet = this.mapChunk.create(c, true, 65535);
} catch (ReflectiveOperationException | IllegalArgumentException e) {
try {
packet = this.mapChunk.create(c, true, 65535, 5);
} catch (ReflectiveOperationException | IllegalArgumentException e1) {
e1.printStackTrace();
}
}
}
if (packet == null) {
PS.debug("Error with PacketPlayOutMapChunk reflection.");
}
this.send.of(con).call(packet);
}
}
for (final Chunk chunk : chunks) {
TaskManager.runTask(new Runnable() {
@Override
public void run() {
try {
chunk.unload(true, false);
} catch (Throwable ignored) {
String worldName = chunk.getWorld().getName();
PS.debug("$4Could not save chunk: " + worldName + ';' + chunk.getX() + ";" + chunk.getZ());
PS.debug("$3 - $4File may be open in another process (e.g. MCEdit)");
PS.debug("$3 - $4" + worldName + "/level.dat or " + worldName
+ "/level_old.dat may be corrupt (try repairing or removing these)");
}
}
});
}
}
public void sendChunk(String worldName, Collection<ChunkLoc> chunkLocations) {
World myWorld = Bukkit.getWorld(worldName);
ArrayList<Chunk> chunks = new ArrayList<>();
for (ChunkLoc loc : chunkLocations) {
if (myWorld.isChunkLoaded(loc.x, loc.z)) {
chunks.add(myWorld.getChunkAt(loc.x, loc.z));
}
}
sendChunk(chunks);
}
}

View File

@ -14,24 +14,24 @@ import java.util.Iterator;
public class SetGenCB { public class SetGenCB {
public static void setGenerator(final World world) throws Exception { public static void setGenerator(World world) throws Exception {
SetupUtils.manager.updateGenerators(); SetupUtils.manager.updateGenerators();
PS.get().removePlotAreas(world.getName()); PS.get().removePlotAreas(world.getName());
final ChunkGenerator gen = world.getGenerator(); ChunkGenerator gen = world.getGenerator();
if (gen == null) { if (gen == null) {
return; return;
} }
final String name = gen.getClass().getCanonicalName(); String name = gen.getClass().getCanonicalName();
boolean set = false; boolean set = false;
for (final GeneratorWrapper<?> wrapper : SetupUtils.generators.values()) { for (GeneratorWrapper<?> wrapper : SetupUtils.generators.values()) {
ChunkGenerator newGen = (ChunkGenerator) wrapper.getPlatformGenerator(); ChunkGenerator newGen = (ChunkGenerator) wrapper.getPlatformGenerator();
if (newGen == null) { if (newGen == null) {
newGen = (ChunkGenerator) wrapper; newGen = (ChunkGenerator) wrapper;
} }
if (newGen.getClass().getCanonicalName().equals(name)) { if (newGen.getClass().getCanonicalName().equals(name)) {
// set generator // set generator
final Field generator = world.getClass().getDeclaredField("generator"); Field generator = world.getClass().getDeclaredField("generator");
final Field populators = world.getClass().getDeclaredField("populators"); Field populators = world.getClass().getDeclaredField("populators");
generator.setAccessible(true); generator.setAccessible(true);
populators.setAccessible(true); populators.setAccessible(true);
// Set populators (just in case) // Set populators (just in case)
@ -45,10 +45,10 @@ public class SetGenCB {
} }
} }
if (!set) { if (!set) {
final Iterator<BlockPopulator> iter = world.getPopulators().iterator(); Iterator<BlockPopulator> iterator = world.getPopulators().iterator();
while (iter.hasNext()) { while (iterator.hasNext()) {
if (iter.next() instanceof BukkitAugmentedGenerator) { if (iterator.next() instanceof BukkitAugmentedGenerator) {
iter.remove(); iterator.remove();
} }
} }
} }

View File

@ -0,0 +1,187 @@
package com.plotsquared.bukkit.util.block;
import com.intellectualcrafters.plot.object.PlotBlock;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.StringMan;
import com.intellectualcrafters.plot.util.block.BasicLocalBlockQueue;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
public class BukkitLocalQueue<T> extends BasicLocalBlockQueue<T> {
public BukkitLocalQueue(String world) {
super(world);
}
@Override
public LocalChunk<T> getLocalChunk(int x, int z) {
return (LocalChunk<T>) new BasicLocalChunk(this, x, z) {
// Custom stuff?
};
}
@Override
public void optimize() {
}
@Override
public PlotBlock getBlock(int x, int y, int z) {
World worldObj = Bukkit.getWorld(getWorld());
Block block = worldObj.getBlockAt(x, y, z);
if (block == null) {
return PlotBlock.get(0, 0);
}
int id = block.getTypeId();
if (id == 0) {
return PlotBlock.get(0, 0);
}
return PlotBlock.get(id, block.getData());
}
@Override
public void refreshChunk(int x, int z) {
World worldObj = Bukkit.getWorld(getWorld());
worldObj.refreshChunk(x, z);
}
@Override
public void fixChunkLighting(int x, int z) {
// Do nothing
}
@Override
public final void regenChunk(int x, int z) {
World worldObj = Bukkit.getWorld(getWorld());
worldObj.regenerateChunk(x, z);
}
@Override
public final void setComponents(LocalChunk<T> lc) {
setBlocks(lc);
setBiomes(lc);
}
public World getBukkitWorld() {
return Bukkit.getWorld(getWorld());
}
public Chunk getChunk(int x, int z) {
return getBukkitWorld().getChunkAt(x, z);
}
public void setBlocks(LocalChunk<T> lc) {
World worldObj = Bukkit.getWorld(getWorld());
Chunk chunk = worldObj.getChunkAt(lc.getX(), lc.getZ());
chunk.load(true);
for (int layer = 0; layer < lc.blocks.length; layer++) {
PlotBlock[] blocksLayer = (PlotBlock[]) lc.blocks[layer];
if (blocksLayer != null) {
for (int j = 0; j < blocksLayer.length; j++) {
PlotBlock block = blocksLayer[j];
if (block != null) {
int x = MainUtil.x_loc[layer][j];
int y = MainUtil.y_loc[layer][j];
int z = MainUtil.z_loc[layer][j];
Block existing = chunk.getBlock(x, y, z);
int existingId = existing.getTypeId();
if (existingId == block.id) {
if (existingId == 0) {
continue;
}
if (existing.getData() == block.data) {
continue;
}
}
existing.setTypeIdAndData(block.id, block.data, false);
}
}
}
}
}
public void setBiomes(LocalChunk<T> lc) {
if (lc.biomes != null) {
World worldObj = Bukkit.getWorld(getWorld());
int bx = lc.getX() << 4;
int bz = lc.getX() << 4;
String last = null;
Biome biome = null;
for (int x = 0; x < lc.biomes.length; x++) {
String[] biomes2 = lc.biomes[x];
if (biomes2 != null) {
for (int y = 0; y < biomes2.length; y++) {
String biomeStr = biomes2[y];
if (biomeStr != null) {
if (last == null || !StringMan.isEqual(last, biomeStr)) {
biome = Biome.valueOf(biomeStr.toUpperCase());
}
worldObj.setBiome(bx, bz, biome);
}
}
}
}
}
}
private Field fieldNeighbors;
private Method chunkGetHandle;
/**
* Exploiting a bug in the vanilla lighting algorithm for faster block placement
* - Could have been achieved without reflection by force unloading specific chunks
* - Much faster just setting the variable manually though
* @param chunk
* @return
*/
protected Object[] disableLighting(Chunk chunk) {
try {
if (chunkGetHandle == null) {
chunkGetHandle = chunk.getClass().getDeclaredMethod("getHandle");
chunkGetHandle.setAccessible(true);
}
Object nmsChunk = chunkGetHandle.invoke(chunk);
if (fieldNeighbors == null) {
fieldNeighbors = nmsChunk.getClass().getDeclaredField("neighbors");
fieldNeighbors.setAccessible(true);
}
Object value = fieldNeighbors.get(nmsChunk);
fieldNeighbors.set(nmsChunk, 0);
return new Object[] {nmsChunk, value};
} catch (Throwable ignore) {}
return null;
}
protected void disableLighting(Object[] disableResult) {
if (disableResult != null) {
try {
fieldNeighbors.set(disableResult[0], 0);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
protected void resetLighting(Object[] disableResult) {
if (disableResult != null) {
try {
fieldNeighbors.set(disableResult[0], disableResult[1]);
} catch (Throwable ignore) {
ignore.printStackTrace();
}
}
}
protected void enableLighting(Object[] disableResult) {
if (disableResult != null) {
try {
fieldNeighbors.set(disableResult[0], 0x739C0);
} catch (Throwable ignore) {}
}
}
}

View File

@ -0,0 +1,135 @@
package com.plotsquared.bukkit.util.block;
import com.intellectualcrafters.plot.object.ChunkWrapper;
import com.intellectualcrafters.plot.object.PlotBlock;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.ReflectionUtils;
import com.intellectualcrafters.plot.util.TaskManager;
import com.plotsquared.bukkit.util.SendChunk;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
public class BukkitLocalQueue_1_7 extends BukkitLocalQueue<PlotBlock[]> {
private final ReflectionUtils.RefClass classBlock = getRefClass("{nms}.Block");
private final ReflectionUtils.RefClass classChunk = getRefClass("{nms}.Chunk");
private final ReflectionUtils.RefClass classWorld = getRefClass("{nms}.World");
private final ReflectionUtils.RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
private final ReflectionUtils.RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
private final ReflectionUtils.RefMethod methodGetHandle;
private final ReflectionUtils.RefMethod methodGetHandleChunk;
private final ReflectionUtils.RefMethod methodGetChunkAt;
private final ReflectionUtils.RefMethod methodA;
private final ReflectionUtils.RefMethod methodGetById;
private final ReflectionUtils.RefMethod methodInitLighting;
private final SendChunk sendChunk;
private final HashMap<ChunkWrapper, Chunk> toUpdate = new HashMap<>();
public BukkitLocalQueue_1_7(String world) throws NoSuchMethodException, ClassNotFoundException, NoSuchFieldException {
super(world);
this.methodGetHandle = this.classCraftWorld.getMethod("getHandle");
this.methodGetChunkAt = this.classWorld.getMethod("getChunkAt", int.class, int.class);
this.methodA = this.classChunk.getMethod("a", int.class, int.class, int.class, this.classBlock, int.class);
this.methodGetById = this.classBlock.getMethod("getById", int.class);
this.methodGetHandleChunk = this.classCraftChunk.getMethod("getHandle");
this.methodInitLighting = this.classChunk.getMethod("initLighting");
this.sendChunk = new SendChunk();
TaskManager.runTaskRepeat(new Runnable() {
@Override
public void run() {
if (BukkitLocalQueue_1_7.this.toUpdate.isEmpty()) {
return;
}
int count = 0;
ArrayList<Chunk> chunks = new ArrayList<>();
Iterator<Map.Entry<ChunkWrapper, Chunk>> i = BukkitLocalQueue_1_7.this.toUpdate.entrySet().iterator();
while (i.hasNext() && (count < 128)) {
chunks.add(i.next().getValue());
i.remove();
count++;
}
if (count == 0) {
return;
}
update(chunks);
}
}, 1);
MainUtil.initCache();
}
public void update(Collection<Chunk> chunks) {
if (chunks.isEmpty()) {
return;
}
if (!MainUtil.canSendChunk) {
for (Chunk chunk : chunks) {
chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ());
chunk.unload(true, false);
chunk.load();
}
return;
}
try {
this.sendChunk.sendChunk(chunks);
} catch (Throwable e) {
e.printStackTrace();
MainUtil.canSendChunk = false;
}
}
@Override
public void fixChunkLighting(int x, int z) {
Object c = this.methodGetHandleChunk.of(getChunk(x, z)).call();
this.methodInitLighting.of(c).call();
}
@Override
public void setBlocks(LocalChunk<PlotBlock[]> lc) {
Chunk chunk = getChunk(lc.getX(), lc.getZ());
chunk.load(true);
World world = chunk.getWorld();
ChunkWrapper wrapper = new ChunkWrapper(getWorld(), lc.getX(), lc.getZ());
if (!this.toUpdate.containsKey(wrapper)) {
this.toUpdate.put(wrapper, chunk);
}
Object w = this.methodGetHandle.of(world).call();
Object c = this.methodGetChunkAt.of(w).call(lc.getX(), lc.getZ());
for (int i = 0; i < lc.blocks.length; i++) {
PlotBlock[] result2 = lc.blocks[i];
if (result2 == null) {
continue;
}
for (int j = 0; j < 4096; j++) {
int x = MainUtil.x_loc[i][j];
int y = MainUtil.y_loc[i][j];
int z = MainUtil.z_loc[i][j];
PlotBlock newBlock = result2[j];
if (newBlock != null) {
if (newBlock.id == -1) {
chunk.getBlock(x, y, z).setData(newBlock.data, false);
continue;
}
Object block = this.methodGetById.call(newBlock.id);
this.methodA.of(c).call(x, y, z, block, newBlock.data);
}
}
}
fixChunkLighting(lc.getX(), lc.getZ());
}
@Override
public void refreshChunk(int x, int z) {
update(Arrays.asList(Bukkit.getWorld(getWorld()).getChunkAt(x, z)));
}
}

View File

@ -1,65 +1,61 @@
package com.plotsquared.bukkit.util.block; package com.plotsquared.bukkit.util.block;
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass; import com.intellectualcrafters.plot.object.ChunkWrapper;
import com.intellectualcrafters.plot.object.ChunkLoc;
import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.object.PlotBlock;
import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.PlotChunk; import com.intellectualcrafters.plot.util.ReflectionUtils;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefConstructor;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
import com.intellectualcrafters.plot.util.SetQueue;
import com.intellectualcrafters.plot.util.SetQueue.ChunkWrapper;
import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.TaskManager;
import com.plotsquared.bukkit.util.BukkitUtil;
import com.plotsquared.bukkit.util.SendChunk; import com.plotsquared.bukkit.util.SendChunk;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
public class FastQueue_1_8 extends SlowQueue {
public final RefMethod methodInitLighting; import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
private final RefClass classBlock = getRefClass("{nms}.Block");
private final RefClass classBlockPosition = getRefClass("{nms}.BlockPosition");
private final RefClass classIBlockData = getRefClass("{nms}.IBlockData");
private final RefClass classChunk = getRefClass("{nms}.Chunk");
private final RefClass classWorld = getRefClass("{nms}.World");
private final RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
public HashMap<ChunkWrapper, Chunk> toUpdate = new HashMap<>();
private RefMethod methodGetHandle;
private RefMethod methodGetChunkAt;
private RefMethod methodA;
private RefMethod methodGetByCombinedId;
private RefConstructor constructorBlockPosition;
private SendChunk chunksender;
public FastQueue_1_8() throws NoSuchMethodException, RuntimeException { public class BukkitLocalQueue_1_8 extends BukkitLocalQueue<PlotBlock[]> {
methodInitLighting = classChunk.getMethod("initLighting");
constructorBlockPosition = classBlockPosition.getConstructor(int.class, int.class, int.class); private final ReflectionUtils.RefMethod methodInitLighting;
methodGetByCombinedId = classBlock.getMethod("getByCombinedId", int.class); private final ReflectionUtils.RefClass classBlock = getRefClass("{nms}.Block");
methodGetHandle = classCraftWorld.getMethod("getHandle"); private final ReflectionUtils.RefClass classBlockPosition = getRefClass("{nms}.BlockPosition");
methodGetChunkAt = classWorld.getMethod("getChunkAt", int.class, int.class); private final ReflectionUtils.RefClass classIBlockData = getRefClass("{nms}.IBlockData");
methodA = classChunk.getMethod("a", classBlockPosition, classIBlockData); private final ReflectionUtils.RefClass classChunk = getRefClass("{nms}.Chunk");
chunksender = new SendChunk(); private final ReflectionUtils.RefClass classWorld = getRefClass("{nms}.World");
private final ReflectionUtils.RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
private final HashMap<ChunkWrapper, Chunk> toUpdate = new HashMap<>();
private final ReflectionUtils.RefMethod methodGetHandle;
private final ReflectionUtils.RefMethod methodGetChunkAt;
private final ReflectionUtils.RefMethod methodA;
private final ReflectionUtils.RefMethod methodGetByCombinedId;
private final ReflectionUtils.RefConstructor constructorBlockPosition;
private final SendChunk sendChunk;
public BukkitLocalQueue_1_8(String world) throws NoSuchMethodException, ClassNotFoundException, NoSuchFieldException {
super(world);
this.methodInitLighting = this.classChunk.getMethod("initLighting");
this.constructorBlockPosition = this.classBlockPosition.getConstructor(int.class, int.class, int.class);
this.methodGetByCombinedId = this.classBlock.getMethod("getByCombinedId", int.class);
this.methodGetHandle = this.classCraftWorld.getMethod("getHandle");
this.methodGetChunkAt = this.classWorld.getMethod("getChunkAt", int.class, int.class);
this.methodA = this.classChunk.getMethod("a", this.classBlockPosition, this.classIBlockData);
this.sendChunk = new SendChunk();
TaskManager.runTaskRepeat(new Runnable() { TaskManager.runTaskRepeat(new Runnable() {
@Override @Override
public void run() { public void run() {
if (toUpdate.isEmpty()) { if (BukkitLocalQueue_1_8.this.toUpdate.isEmpty()) {
return; return;
} }
int count = 0; int count = 0;
final ArrayList<Chunk> chunks = new ArrayList<Chunk>(); ArrayList<Chunk> chunks = new ArrayList<>();
final Iterator<Entry<ChunkWrapper, Chunk>> i = toUpdate.entrySet().iterator(); Iterator<Map.Entry<ChunkWrapper, Chunk>> i = BukkitLocalQueue_1_8.this.toUpdate.entrySet().iterator();
while (i.hasNext() && (count < 128)) { while (i.hasNext() && count < 128) {
chunks.add(i.next().getValue()); chunks.add(i.next().getValue());
i.remove(); i.remove();
count++; count++;
@ -73,51 +69,32 @@ public class FastQueue_1_8 extends SlowQueue {
MainUtil.initCache(); MainUtil.initCache();
} }
public void update(final Collection<Chunk> chunks) { @Override
if (chunks.isEmpty()) { public void fixChunkLighting(int x, int z) {
return; Object c = this.methodGetHandle.of(getChunk(x, z)).call();
} this.methodInitLighting.of(c).call();
if (!MainUtil.canSendChunk) {
for (final Chunk chunk : chunks) {
chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ());
chunk.unload(true, false);
chunk.load();
}
return;
}
try {
chunksender.sendChunk(chunks);
} catch (final Throwable e) {
e.printStackTrace();
MainUtil.canSendChunk = false;
}
} }
/**
* This should be overriden by any specialized queues
* @param pc
*/
@Override @Override
public void execute(PlotChunk<Chunk> pc) { public void setBlocks(LocalChunk<PlotBlock[]> lc) {
SlowChunk sc = (SlowChunk) pc; Chunk chunk = getChunk(lc.getX(), lc.getZ());
Chunk chunk = pc.getChunk();
ChunkWrapper wrapper = pc.getChunkWrapper();
if (!toUpdate.containsKey(wrapper)) {
toUpdate.put(wrapper, chunk);
}
chunk.load(true); chunk.load(true);
World world = chunk.getWorld(); World world = chunk.getWorld();
final Object w = methodGetHandle.of(world).call(); ChunkWrapper wrapper = new ChunkWrapper(getWorld(), lc.getX(), lc.getZ());
final Object c = methodGetChunkAt.of(w).call(wrapper.x, wrapper.z); if (!this.toUpdate.containsKey(wrapper)) {
for (int i = 0; i < sc.result.length; i++) { this.toUpdate.put(wrapper, chunk);
PlotBlock[] result2 = sc.result[i]; }
Object w = this.methodGetHandle.of(world).call();
Object c = this.methodGetChunkAt.of(w).call(lc.getX(), lc.getZ());
for (int i = 0; i < lc.blocks.length; i++) {
PlotBlock[] result2 = lc.blocks[i];
if (result2 == null) { if (result2 == null) {
continue; continue;
} }
for (int j = 0; j < 4096; j++) { for (int j = 0; j < 4096; j++) {
final int x = MainUtil.x_loc[i][j]; int x = MainUtil.x_loc[i][j];
final int y = MainUtil.y_loc[i][j]; int y = MainUtil.y_loc[i][j];
final int z = MainUtil.z_loc[i][j]; int z = MainUtil.z_loc[i][j];
PlotBlock newBlock = result2[j]; PlotBlock newBlock = result2[j];
if (newBlock.id == -1) { if (newBlock.id == -1) {
chunk.getBlock(x, y, z).setData(newBlock.data, false); chunk.getBlock(x, y, z).setData(newBlock.data, false);
@ -161,8 +138,8 @@ public class FastQueue_1_8 extends SlowQueue {
case 29: case 29:
case 33: case 33:
case 151: case 151:
case 178: { case 178:
final Block block = world.getBlockAt(x, y, z); Block block = world.getBlockAt(x, y, z);
if (block.getData() == newBlock.data) { if (block.getData() == newBlock.data) {
if (block.getTypeId() != newBlock.id) { if (block.getTypeId() != newBlock.id) {
block.setTypeId(newBlock.id, false); block.setTypeId(newBlock.id, false);
@ -176,11 +153,10 @@ public class FastQueue_1_8 extends SlowQueue {
} }
continue; continue;
} }
}
// Start data value shortcut // Start data value shortcut
final Block block = world.getBlockAt(x, y, z); Block block = world.getBlockAt(x, y, z);
final int currentId = block.getTypeId(); int currentId = block.getTypeId();
if (currentId == newBlock.id) { if (currentId == newBlock.id) {
switch (newBlock.id) { switch (newBlock.id) {
case 0: case 0:
@ -263,10 +239,9 @@ public class FastQueue_1_8 extends SlowQueue {
case 189: case 189:
case 190: case 190:
case 191: case 191:
case 192: { case 192:
continue; continue;
} }
}
if (block.getData() == newBlock.data) { if (block.getData() == newBlock.data) {
return; return;
} }
@ -311,7 +286,7 @@ public class FastQueue_1_8 extends SlowQueue {
case 29: case 29:
case 33: case 33:
case 151: case 151:
case 178: { case 178:
if (block.getData() == newBlock.data) { if (block.getData() == newBlock.data) {
block.setTypeId(newBlock.id, false); block.setTypeId(newBlock.id, false);
} else { } else {
@ -319,66 +294,44 @@ public class FastQueue_1_8 extends SlowQueue {
} }
continue; continue;
} }
}
// End blockstate workaround // // End blockstate workaround //
// check sign // check sign
final Object pos = constructorBlockPosition.create(x, y, z); Object pos = null;
final Object combined = methodGetByCombinedId.call(newBlock.id + (newBlock.data << 12)); try {
methodA.of(chunk).call(pos, combined); pos = this.constructorBlockPosition.create(x, y, z);
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
Object combined = this.methodGetByCombinedId.call(newBlock.id + (newBlock.data << 12));
this.methodA.of(chunk).call(pos, combined);
} }
} }
int[][] biomes = sc.biomes; fixChunkLighting(lc.getX(), lc.getZ());
Biome[] values = Biome.values();
if (biomes != null) {
for (int x = 0; x < 16; x++) {
int[] array = biomes[x];
if (array == null) {
continue;
} }
for (int z = 0; z < 16; z++) {
int biome = array[z]; public void update(Collection<Chunk> chunks) {
if (biome == 0) { if (chunks.isEmpty()) {
continue; return;
} }
chunk.getBlock(x, 0, z).setBiome(values[biome]); if (!MainUtil.canSendChunk) {
for (Chunk chunk : chunks) {
chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ());
chunk.unload(true, false);
chunk.load();
} }
return;
} }
try {
this.sendChunk.sendChunk(chunks);
} catch (Throwable e) {
e.printStackTrace();
MainUtil.canSendChunk = false;
} }
} }
/**
* This should be overridden by any specialized queues
* @param wrap
*/
@Override @Override
public PlotChunk<Chunk> getChunk(ChunkWrapper wrap) { public void refreshChunk(int x, int z) {
return new SlowChunk(wrap); update(Arrays.asList(Bukkit.getWorld(getWorld()).getChunkAt(x, z)));
}
/**
* This should be overridden by any specialized queues
* @param fixAll
*/
@Override
public boolean fixLighting(PlotChunk<Chunk> chunk, boolean fixAll) {
Object c = methodGetHandle.of(chunk.getChunk()).call();
methodInitLighting.of(c).call();
return true;
}
/**
* This should be overridden by any specialized queues
* @param locs
*/
@Override
public void sendChunk(String world, Collection<ChunkLoc> locs) {
World worldObj = BukkitUtil.getWorld(world);
for (ChunkLoc loc : locs) {
ChunkWrapper wrapper = SetQueue.IMP.new ChunkWrapper(world, loc.x, loc.z);
if (!toUpdate.containsKey(wrapper)) {
toUpdate.put(wrapper, worldObj.getChunkAt(loc.x, loc.z));
}
}
} }
} }

View File

@ -0,0 +1,537 @@
package com.plotsquared.bukkit.util.block;
import com.intellectualcrafters.plot.object.ChunkLoc;
import com.intellectualcrafters.plot.object.ChunkWrapper;
import com.intellectualcrafters.plot.object.PseudoRandom;
import com.intellectualcrafters.plot.util.ChunkManager;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.ReflectionUtils;
import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.block.BasicLocalBlockQueue;
import com.plotsquared.bukkit.util.SendChunk;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
public class BukkitLocalQueue_1_8_3 extends BukkitLocalQueue<char[]> {
private final SendChunk sendChunk;
private final HashMap<ChunkWrapper, Chunk> toUpdate = new HashMap<>();
private final ReflectionUtils.RefMethod methodGetHandleChunk;
private final ReflectionUtils.RefMethod methodGetHandleWorld;
private final ReflectionUtils.RefMethod methodInitLighting;
private final ReflectionUtils.RefConstructor classBlockPositionConstructor;
private final ReflectionUtils.RefConstructor classChunkSectionConstructor;
private final ReflectionUtils.RefMethod methodX;
private final ReflectionUtils.RefMethod methodAreNeighborsLoaded;
private final ReflectionUtils.RefField fieldSections;
private final ReflectionUtils.RefField fieldWorld;
private final ReflectionUtils.RefMethod methodGetIdArray;
private final ReflectionUtils.RefMethod methodGetWorld;
private final ReflectionUtils.RefField tileEntityListTick;
public BukkitLocalQueue_1_8_3(String world) throws NoSuchMethodException, ClassNotFoundException, NoSuchFieldException {
super(world);
ReflectionUtils.RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
ReflectionUtils.RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
ReflectionUtils.RefClass classChunk = getRefClass("{nms}.Chunk");
this.methodInitLighting = classChunk.getMethod("initLighting");
ReflectionUtils.RefClass classBlockPosition = getRefClass("{nms}.BlockPosition");
this.classBlockPositionConstructor = classBlockPosition.getConstructor(int.class, int.class, int.class);
ReflectionUtils.RefClass classWorld = getRefClass("{nms}.World");
this.methodX = classWorld.getMethod("x", classBlockPosition.getRealClass());
this.fieldSections = classChunk.getField("sections");
this.fieldWorld = classChunk.getField("world");
ReflectionUtils.RefClass classChunkSection = getRefClass("{nms}.ChunkSection");
this.methodGetIdArray = classChunkSection.getMethod("getIdArray");
this.methodAreNeighborsLoaded = classChunk.getMethod("areNeighborsLoaded", int.class);
this.classChunkSectionConstructor = classChunkSection.getConstructor(int.class, boolean.class, char[].class);
this.tileEntityListTick = classWorld.getField("tileEntityList");
this.methodGetHandleWorld = classCraftWorld.getMethod("getHandle");
this.methodGetWorld = classChunk.getMethod("getWorld");
this.sendChunk = new SendChunk();
TaskManager.runTaskRepeat(new Runnable() {
@Override
public void run() {
if (BukkitLocalQueue_1_8_3.this.toUpdate.isEmpty()) {
return;
}
int count = 0;
ArrayList<Chunk> chunks = new ArrayList<>();
Iterator<Map.Entry<ChunkWrapper, Chunk>> i = BukkitLocalQueue_1_8_3.this.toUpdate.entrySet().iterator();
while (i.hasNext() && count < 128) {
chunks.add(i.next().getValue());
i.remove();
count++;
}
if (count == 0) {
return;
}
update(chunks);
}
}, 1);
MainUtil.initCache();
}
@Override
public LocalChunk<char[]> getLocalChunk(int x, int z) {
return new CharLocalChunk_1_8_3(this, x, z);
}
public class CharLocalChunk_1_8_3 extends CharLocalChunk {
public short[] count;
public short[] air;
public short[] relight;
public CharLocalChunk_1_8_3(BasicLocalBlockQueue parent, int x, int z) {
super(parent, x, z);
this.count = new short[16];
this.air = new short[16];
this.relight = new short[16];
}
@Override
public void setBlock(int x, int y, int z, int id, int data) {
int i = MainUtil.CACHE_I[y][x][z];
int j = MainUtil.CACHE_J[y][x][z];
char[] vs = this.blocks[i];
if (vs == null) {
vs = this.blocks[i] = new char[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = (char) 1;
return;
case 10:
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
this.relight[i]++;
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 30:
case 32:
case 37:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 55:
case 56:
case 57:
case 58:
case 60:
case 7:
case 8:
case 9:
case 73:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 121:
case 129:
case 133:
case 165:
case 166:
case 170:
case 172:
case 173:
case 174:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192:
vs[j] = (char) (id << 4);
return;
case 130:
case 76:
case 62:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
case 50:
if (data < 2) {
data = 2;
}
default:
vs[j] = (char) ((id << 4) + data);
return;
}
}
public char[] getIdArray(int i) {
return this.blocks[i];
}
public int getCount(int i) {
return this.count[i];
}
public int getAir(int i) {
return this.air[i];
}
public void setCount(int i, short value) {
this.count[i] = value;
}
public int getRelight(int i) {
return this.relight[i];
}
public int getTotalCount() {
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.count[i];
}
return total;
}
public int getTotalRelight() {
if (getTotalCount() == 0) {
Arrays.fill(this.count, (short) 1);
Arrays.fill(this.relight, Short.MAX_VALUE);
return Short.MAX_VALUE;
}
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.relight[i];
}
return total;
}
}
@Override
public void setBlocks(LocalChunk lc) {
CharLocalChunk_1_8_3 fs = (CharLocalChunk_1_8_3) lc;
Chunk chunk = getChunk(lc.getX(), lc.getZ());
chunk.load(true);
World world = chunk.getWorld();
ChunkWrapper wrapper = new ChunkWrapper(getWorld(), lc.getX(), lc.getZ());
if (!this.toUpdate.containsKey(wrapper)) {
this.toUpdate.put(wrapper, chunk);
}
try {
boolean flag = world.getEnvironment() == World.Environment.NORMAL;
// Sections
Method getHandle = chunk.getClass().getDeclaredMethod("getHandle");
Object c = getHandle.invoke(chunk);
Object w = this.methodGetWorld.of(c).call();
Class<?> clazz = c.getClass();
Field sections1 = clazz.getDeclaredField("sections");
sections1.setAccessible(true);
Field tileEntities = clazz.getDeclaredField("tileEntities");
Field entitySlices = clazz.getDeclaredField("entitySlices");
Object[] sections = (Object[]) sections1.get(c);
Map<?, ?> tiles = (Map<?, ?>) tileEntities.get(c);
Collection<?>[] entities = (Collection<?>[]) entitySlices.get(c);
Method getX = null;
Method getY = null;
Method getZ = null;
// Trim tiles
boolean removed = false;
Set<Map.Entry<?, ?>> entrySet = (Set<Map.Entry<?, ?>>) (Set<?>) tiles.entrySet();
Iterator<Map.Entry<?, ?>> iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry<?, ?> tile = iterator.next();
Object pos = tile.getKey();
if (getX == null) {
Class<? extends Object> clazz2 = pos.getClass().getSuperclass();
getX = clazz2.getDeclaredMethod("getX");
getY = clazz2.getDeclaredMethod("getY");
getZ = clazz2.getDeclaredMethod("getZ");
}
int lx = (int) getX.invoke(pos) & 15;
int ly = (int) getY.invoke(pos);
int lz = (int) getZ.invoke(pos) & 15;
int j = MainUtil.CACHE_I[ly][lx][lz];
int k = MainUtil.CACHE_J[ly][lx][lz];
char[] array = fs.getIdArray(j);
if (array == null) {
continue;
}
if (array[k] != 0) {
removed = true;
iterator.remove();
}
}
if (removed) {
((Collection) this.tileEntityListTick.of(w).get()).clear();
}
// Trim entities
for (int i = 0; i < 16; i++) {
if ((entities[i] != null) && (fs.getCount(i) >= 4096)) {
entities[i].clear();
}
}
// Efficiently merge sections
for (int j = 0; j < sections.length; j++) {
if (fs.getCount(j) == 0) {
continue;
}
char[] newArray = fs.getIdArray(j);
if (newArray == null) {
continue;
}
Object section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
section = sections[j] = newChunkSection(j << 4, flag, newArray);
continue;
}
char[] currentArray = getIdArray(section);
boolean fill = true;
for (int k = 0; k < newArray.length; k++) {
char n = newArray[k];
switch (n) {
case 0:
fill = false;
continue;
case 1:
fill = false;
currentArray[k] = 0;
continue;
default:
currentArray[k] = n;
continue;
}
}
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
}
// Clear
} catch (IllegalArgumentException | SecurityException | ReflectiveOperationException e) {
e.printStackTrace();
}
fixLighting(chunk, fs, true);
}
public Object newChunkSection(int i, boolean flag, char[] ids) throws ReflectiveOperationException {
return this.classChunkSectionConstructor.create(i, flag, ids);
}
public char[] getIdArray(Object obj) {
return (char[]) this.methodGetIdArray.of(obj).call();
}
@Override
public void fixChunkLighting(int x, int z) {
Object c = this.methodGetHandleChunk.of(getChunk(x, z)).call();
this.methodInitLighting.of(c).call();
}
public boolean fixLighting(Chunk chunk, CharLocalChunk_1_8_3 bc, boolean fixAll) {
try {
if (!chunk.isLoaded()) {
chunk.load(false);
} else {
chunk.unload(true, false);
chunk.load(false);
}
// Initialize lighting
Object c = this.methodGetHandleChunk.of(chunk).call();
if (fixAll && !(boolean) this.methodAreNeighborsLoaded.of(c).call(1)) {
World world = chunk.getWorld();
ChunkWrapper wrapper = new ChunkWrapper(getWorld(), chunk.getX(), chunk.getZ());
for (int x = wrapper.x - 1; x <= wrapper.x + 1; x++) {
for (int z = wrapper.z - 1; z <= wrapper.z + 1; z++) {
if (x != 0 && z != 0) {
Chunk other = world.getChunkAt(x, z);
while (!other.isLoaded()) {
other.load(true);
}
ChunkManager.manager.loadChunk(wrapper.world, new ChunkLoc(x, z), true);
}
}
}
/*
if (!(boolean) methodAreNeighborsLoaded.of(c).call(1)) {
return false;
}
*/
}
this.methodInitLighting.of(c).call();
if (bc.getTotalRelight() == 0 && !fixAll) {
return true;
}
Object[] sections = (Object[]) this.fieldSections.of(c).get();
Object w = this.fieldWorld.of(c).get();
int X = chunk.getX() << 4;
int Z = chunk.getZ() << 4;
ReflectionUtils.RefMethod.RefExecutor relight = this.methodX.of(w);
for (int j = 0; j < sections.length; j++) {
Object section = sections[j];
if (section == null) {
continue;
}
if ((bc.getRelight(j) == 0 && !fixAll) || bc.getCount(j) == 0 || (bc.getCount(j) >= 4096 && bc.getAir(j) == 0)) {
continue;
}
char[] array = getIdArray(section);
int l = PseudoRandom.random.random(2);
for (int k = 0; k < array.length; k++) {
int i = array[k];
if (i < 16) {
continue;
}
short id = (short) (i >> 4);
switch (id) { // Lighting
default:
if (!fixAll) {
continue;
}
if ((k & 1) == l) {
l = 1 - l;
continue;
}
case 10:
case 11:
case 39:
case 40:
case 50:
case 51:
case 62:
case 74:
case 76:
case 89:
case 122:
case 124:
case 130:
case 138:
case 169:
int x = MainUtil.x_loc[j][k];
int y = MainUtil.y_loc[j][k];
int z = MainUtil.z_loc[j][k];
if (isSurrounded(sections, x, y, z)) {
continue;
}
Object pos = this.classBlockPositionConstructor.create(X + x, y, Z + z);
relight.call(pos);
}
}
}
return true;
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
public boolean isSurrounded(Object[] sections, int x, int y, int z) {
return isSolid(getId(sections, x, y + 1, z))
&& isSolid(getId(sections, x + 1, y - 1, z))
&& isSolid(getId(sections, x - 1, y, z))
&& isSolid(getId(sections, x, y, z + 1))
&& isSolid(getId(sections, x, y, z - 1));
}
public boolean isSolid(int i) {
return i != 0 && Material.getMaterial(i).isOccluding();
}
public int getId(Object[] sections, int x, int y, int z) {
if (x < 0 || x > 15 || z < 0 || z > 15) {
return 1;
}
if (y < 0 || y > 255) {
return 1;
}
int i = MainUtil.CACHE_I[y][x][z];
Object section = sections[i];
if (section == null) {
return 0;
}
char[] array = getIdArray(section);
int j = MainUtil.CACHE_J[y][x][z];
return array[j] >> 4;
}
public void update(Collection<Chunk> chunks) {
if (chunks.isEmpty()) {
return;
}
if (!MainUtil.canSendChunk) {
for (Chunk chunk : chunks) {
chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ());
chunk.unload(true, false);
chunk.load();
}
return;
}
try {
this.sendChunk.sendChunk(chunks);
} catch (Throwable e) {
e.printStackTrace();
MainUtil.canSendChunk = false;
}
}
@Override
public void refreshChunk(int x, int z) {
update(Arrays.asList(Bukkit.getWorld(getWorld()).getChunkAt(x, z)));
}
}

View File

@ -0,0 +1,494 @@
package com.plotsquared.bukkit.util.block;
import com.intellectualcrafters.plot.object.ChunkWrapper;
import com.intellectualcrafters.plot.object.PseudoRandom;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.ReflectionUtils;
import com.intellectualcrafters.plot.util.block.BasicLocalBlockQueue;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
public class BukkitLocalQueue_1_9 extends BukkitLocalQueue<char[]> {
private final Object air;
// private final HashMap<ChunkWrapper, Chunk> toUpdate = new HashMap<>();
private final ReflectionUtils.RefMethod methodGetHandleChunk;
private final ReflectionUtils.RefMethod methodInitLighting;
private final ReflectionUtils.RefConstructor classBlockPositionConstructor;
private final ReflectionUtils.RefConstructor classChunkSectionConstructor;
private final ReflectionUtils.RefMethod methodW;
private final ReflectionUtils.RefMethod methodAreNeighborsLoaded;
private final ReflectionUtils.RefField fieldSections;
private final ReflectionUtils.RefField fieldWorld;
private final ReflectionUtils.RefMethod methodGetBlocks;
private final ReflectionUtils.RefMethod methodGetType;
private final ReflectionUtils.RefMethod methodSetType;
private final ReflectionUtils.RefMethod methodGetCombinedId;
private final ReflectionUtils.RefMethod methodGetByCombinedId;
private final ReflectionUtils.RefMethod methodGetWorld;
private final ReflectionUtils.RefField tileEntityListTick;
public BukkitLocalQueue_1_9(String world) throws NoSuchMethodException, ClassNotFoundException, NoSuchFieldException {
super(world);
ReflectionUtils.RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
ReflectionUtils.RefClass classChunk = getRefClass("{nms}.Chunk");
this.methodInitLighting = classChunk.getMethod("initLighting");
ReflectionUtils.RefClass classBlockPosition = getRefClass("{nms}.BlockPosition");
this.classBlockPositionConstructor = classBlockPosition.getConstructor(int.class, int.class, int.class);
ReflectionUtils.RefClass classWorld = getRefClass("{nms}.World");
this.tileEntityListTick = classWorld.getField("tileEntityListTick");
this.methodGetWorld = classChunk.getMethod("getWorld");
this.methodW = classWorld.getMethod("w", classBlockPosition.getRealClass());
this.fieldSections = classChunk.getField("sections");
this.fieldWorld = classChunk.getField("world");
ReflectionUtils.RefClass classBlock = getRefClass("{nms}.Block");
ReflectionUtils.RefClass classIBlockData = getRefClass("{nms}.IBlockData");
this.methodGetCombinedId = classBlock.getMethod("getCombinedId", classIBlockData.getRealClass());
this.methodGetByCombinedId = classBlock.getMethod("getByCombinedId", int.class);
ReflectionUtils.RefClass classChunkSection = getRefClass("{nms}.ChunkSection");
this.methodGetBlocks = classChunkSection.getMethod("getBlocks");
this.methodGetType = classChunkSection.getMethod("getType", int.class, int.class, int.class);
this.methodSetType = classChunkSection.getMethod("setType", int.class, int.class, int.class, classIBlockData.getRealClass());
this.methodAreNeighborsLoaded = classChunk.getMethod("areNeighborsLoaded", int.class);
this.classChunkSectionConstructor = classChunkSection.getConstructor(int.class, boolean.class, char[].class);
this.air = this.methodGetByCombinedId.call(0);
MainUtil.initCache();
}
@Override
public LocalChunk<char[]> getLocalChunk(int x, int z) {
return new CharLocalChunk_1_8_3(this, x, z);
}
public class CharLocalChunk_1_8_3 extends CharLocalChunk {
public short[] count;
public short[] air;
public short[] relight;
public CharLocalChunk_1_8_3(BasicLocalBlockQueue parent, int x, int z) {
super(parent, x, z);
this.count = new short[16];
this.air = new short[16];
this.relight = new short[16];
}
@Override
public void setBlock(int x, int y, int z, int id, int data) {
int i = MainUtil.CACHE_I[y][x][z];
int j = MainUtil.CACHE_J[y][x][z];
char[] vs = this.blocks[i];
if (vs == null) {
vs = this.blocks[i] = new char[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = (char) 1;
return;
case 10:
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
this.relight[i]++;
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 30:
case 32:
case 37:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 55:
case 56:
case 57:
case 58:
case 60:
case 7:
case 8:
case 9:
case 73:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 121:
case 129:
case 133:
case 165:
case 166:
case 170:
case 172:
case 173:
case 174:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192:
vs[j] = (char) (id << 4);
return;
case 130:
case 76:
case 62:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
case 50:
if (data < 2) {
data = 2;
}
default:
vs[j] = (char) ((id << 4) + data);
return;
}
}
public char[] getIdArray(int i) {
return this.blocks[i];
}
public int getCount(int i) {
return this.count[i];
}
public int getAir(int i) {
return this.air[i];
}
public void setCount(int i, short value) {
this.count[i] = value;
}
public int getRelight(int i) {
return this.relight[i];
}
public int getTotalCount() {
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.count[i];
}
return total;
}
public int getTotalRelight() {
if (getTotalCount() == 0) {
Arrays.fill(this.count, (short) 1);
Arrays.fill(this.relight, Short.MAX_VALUE);
return Short.MAX_VALUE;
}
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.relight[i];
}
return total;
}
}
@Override
public void setBlocks(LocalChunk lc) {
CharLocalChunk_1_8_3 fs = (CharLocalChunk_1_8_3) lc;
Chunk chunk = getChunk(lc.getX(), lc.getZ());
chunk.load(true);
World world = chunk.getWorld();
try {
boolean flag = world.getEnvironment() == World.Environment.NORMAL;
// Sections
Method getHandle = chunk.getClass().getDeclaredMethod("getHandle");
Object c = getHandle.invoke(chunk);
Object w = this.methodGetWorld.of(c).call();
Class<? extends Object> clazz = c.getClass();
Field sf = clazz.getDeclaredField("sections");
sf.setAccessible(true);
Field tf = clazz.getDeclaredField("tileEntities");
Field entitySlices = clazz.getDeclaredField("entitySlices");
Object[] sections = (Object[]) sf.get(c);
Map<?, ?> tiles = (Map<?, ?>) tf.get(c);
Collection<?>[] entities = (Collection<?>[]) entitySlices.get(c);
Method xm = null;
Method ym = null;
Method zm = null;
// Trim tiles
Collection tickList = ((Collection) this.tileEntityListTick.of(w).get());
Set<Map.Entry<?, ?>> entrySet = (Set<Map.Entry<?, ?>>) (Set<?>) tiles.entrySet();
Iterator<Map.Entry<?, ?>> iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry<?, ?> tile = iterator.next();
Object pos = tile.getKey();
if (xm == null) {
Class<?> clazz2 = pos.getClass().getSuperclass();
xm = clazz2.getDeclaredMethod("getX");
ym = clazz2.getDeclaredMethod("getY");
zm = clazz2.getDeclaredMethod("getZ");
}
int lx = (int) xm.invoke(pos) & 15;
int ly = (int) ym.invoke(pos);
int lz = (int) zm.invoke(pos) & 15;
int j = MainUtil.CACHE_I[ly][lx][lz];
int k = MainUtil.CACHE_J[ly][lx][lz];
char[] array = fs.getIdArray(j);
if (array == null) {
continue;
}
if (array[k] != 0) {
tickList.remove(tile.getValue());
iterator.remove();
}
}
// Trim entities
for (int i = 0; i < 16; i++) {
if (entities[i] != null && fs.getCount(i) >= 4096) {
entities[i].clear();
}
}
// Efficiently merge sections
for (int j = 0; j < sections.length; j++) {
if (fs.getCount(j) == 0) {
continue;
}
char[] newArray = fs.getIdArray(j);
if (newArray == null) {
continue;
}
Object section = sections[j];
if (section == null || fs.getCount(j) >= 4096) {
section = sections[j] = newChunkSection(j << 4, flag, fs.getIdArray(j));
continue;
}
Object currentArray = getBlocks(section);
ReflectionUtils.RefMethod.RefExecutor setType = this.methodSetType.of(section);
boolean fill = true;
for (int k = 0; k < newArray.length; k++) {
char n = newArray[k];
switch (n) {
case 0:
fill = false;
continue;
case 1: {
fill = false;
int x = MainUtil.x_loc[j][k];
int y = MainUtil.y_loc[j][k];
int z = MainUtil.z_loc[j][k];
setType.call(x, y & 15, z, this.air);
continue;
}
default:
int x = MainUtil.x_loc[j][k];
int y = MainUtil.y_loc[j][k];
int z = MainUtil.z_loc[j][k];
int id = n >> 4;
int data = n & 15;
Object iBlock = this.methodGetByCombinedId.call((int) (id & 0xFFF) + (data << 12));
setType.call(x, y & 15, z, iBlock);
}
}
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
}
// Clear
} catch (IllegalArgumentException | SecurityException | ReflectiveOperationException e) {
e.printStackTrace();
}
fixLighting(chunk, fs, true);
refreshChunk(fs.getX(), fs.getZ());
}
public Object newChunkSection(int i, boolean flag, char[] ids) throws ReflectiveOperationException {
return this.classChunkSectionConstructor.create(i, flag, ids);
}
public Object getBlocks(Object obj) {
return this.methodGetBlocks.of(obj).call();
}
@Override
public void fixChunkLighting(int x, int z) {
Object c = this.methodGetHandleChunk.of(getChunk(x, z)).call();
this.methodInitLighting.of(c).call();
}
public boolean fixLighting(Chunk chunk, CharLocalChunk_1_8_3 bc, boolean fixAll) {
try {
if (!chunk.isLoaded()) {
chunk.load(false);
} else {
chunk.unload(true, false);
chunk.load(false);
}
// Initialize lighting
Object c = this.methodGetHandleChunk.of(chunk).call();
ChunkWrapper wrapper = new ChunkWrapper(getWorld(), bc.getX(), bc.getZ());
Object[] result = disableLighting(chunk);
enableLighting(result);
this.methodInitLighting.of(c).call();
if (bc.getTotalRelight() != 0 || fixAll) {
Object[] sections = (Object[]) this.fieldSections.of(c).get();
Object w = this.fieldWorld.of(c).get();
int X = chunk.getX() << 4;
int Z = chunk.getZ() << 4;
ReflectionUtils.RefMethod.RefExecutor relight = this.methodW.of(w);
for (int j = 0; j < sections.length; j++) {
Object section = sections[j];
if (section == null) {
continue;
}
if (bc.getRelight(j) == 0 && !fixAll || bc.getCount(j) == 0 || bc.getCount(j) >= 4096 && bc.getAir(j) == 0) {
continue;
}
char[] array = bc.getIdArray(j);
if (array != null) {
int l = PseudoRandom.random.random(2);
for (int k = 0; k < array.length; k++) {
int i = array[k];
if (i < 16) {
continue;
}
short id = (short) (i >> 4);
switch (id) { // Lighting
default:
if (!fixAll) {
continue;
}
if ((k & 1) == l) {
l = 1 - l;
continue;
}
case 10:
case 11:
case 39:
case 40:
case 50:
case 51:
case 62:
case 74:
case 76:
case 89:
case 122:
case 124:
case 130:
case 138:
case 169:
int x = MainUtil.x_loc[j][k];
int y = MainUtil.y_loc[j][k];
int z = MainUtil.z_loc[j][k];
if (isSurrounded(bc.blocks, x, y, z)) {
continue;
}
Object pos = this.classBlockPositionConstructor.create(X + x, y, Z + z);
relight.call(pos);
}
}
}
}
}
resetLighting(result);
return true;
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
@Override
public void refreshChunk(int x, int z) {
getBukkitWorld().refreshChunk(x, z);
}
public boolean isSurrounded(char[][] sections, int x, int y, int z) {
return isSolid(getId(sections, x, y + 1, z))
&& isSolid(getId(sections, x + 1, y - 1, z))
&& isSolid(getId(sections, x - 1, y, z))
&& isSolid(getId(sections, x, y, z + 1))
&& isSolid(getId(sections, x, y, z - 1));
}
public boolean isSolid(int i) {
if (i != 0) {
Material material = Material.getMaterial(i);
return material != null && Material.getMaterial(i).isOccluding();
}
return false;
}
public int getId(char[] section, int x, int y, int z) {
if (section == null) {
return 0;
}
int j = MainUtil.CACHE_J[y][x][z];
return section[j] >> 4;
}
public int getId(char[][] sections, int x, int y, int z) {
if (x < 0 || x > 15 || z < 0 || z > 15) {
return 1;
}
if (y < 0 || y > 255) {
return 1;
}
int i = MainUtil.CACHE_I[y][x][z];
char[] section = sections[i];
if (section == null) {
return 0;
}
return getId(section, x, y, z);
}
}

View File

@ -0,0 +1,194 @@
package com.plotsquared.bukkit.util.block;
import com.intellectualcrafters.plot.object.ChunkWrapper;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.PlotBlock;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.block.ScopedLocalBlockQueue;
import com.plotsquared.bukkit.util.BukkitUtil;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import org.bukkit.generator.ChunkGenerator.ChunkData;
import org.bukkit.material.MaterialData;
public class GenChunk extends ScopedLocalBlockQueue {
public final Biome[] biomes;
public short[][] result;
public byte[][] result_data;
public ChunkData cd;
public BiomeGrid grid;
public Chunk chunk;
public String world;
public int cx;
public int cz;
public GenChunk(Chunk chunk, ChunkWrapper wrap) {
super(null, new Location(null, 0, 0, 0), new Location(null, 15, 255, 15));
this.biomes = Biome.values();
}
public void setChunk(Chunk chunk) {
this.chunk = chunk;
}
public void setChunk(ChunkWrapper wrap) {
chunk = null;
world = wrap.world;
cx = wrap.x;
cz = wrap.z;
}
public Chunk getChunk() {
if (chunk == null) {
World worldObj = BukkitUtil.getWorld(world);
if (worldObj != null) {
this.chunk = worldObj.getChunkAt(cx, cz);
}
}
return chunk;
}
public ChunkWrapper getChunkWrapper() {
if (chunk == null) {
return new ChunkWrapper(world, cx, cz);
}
return new ChunkWrapper(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
}
@Override
public void fillBiome(String biomeName) {
if (grid == null) {
return;
}
Biome biome = Biome.valueOf(biomeName.toUpperCase());
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
this.grid.setBiome(x, z, biome);
}
}
}
@Override
public boolean setBiome(int x, int z, String biome) {
return setBiome(x, z, Biome.valueOf(biome.toUpperCase()));
}
public boolean setBiome(int x, int z, int biome) {
if (this.grid != null) {
this.grid.setBiome(x, z, this.biomes[biome]);
return true;
}
return false;
}
public boolean setBiome(int x, int z, Biome biome) {
if (this.grid != null) {
this.grid.setBiome(x, z, biome);
return true;
}
return false;
}
@Override
public boolean setBlock(int x, int y, int z, int id, int data) {
if (this.result == null) {
this.cd.setBlock(x, y, z, id, (byte) data);
return true;
}
int i = MainUtil.CACHE_I[y][x][z];
short[] v = this.result[i];
if (v == null) {
this.result[i] = v = new short[4096];
}
int j = MainUtil.CACHE_J[y][x][z];
v[j] = (short) id;
if (data != 0) {
byte[] vd = this.result_data[i];
if (vd == null) {
this.result_data[i] = vd = new byte[4096];
}
vd[j] = (byte) data;
}
return true;
}
@Override
public PlotBlock getBlock(int x, int y, int z) {
int i = MainUtil.CACHE_I[y][x][z];
if (result == null) {
MaterialData md = cd.getTypeAndData(x, y, z);
return PlotBlock.get(md.getItemTypeId(), md.getData());
}
short[] array = result[i];
if (array == null) {
return PlotBlock.get(0, 0);
}
int j = MainUtil.CACHE_J[y][x][z];
short id = array[j];
if (id == 0) {
return PlotBlock.get(id, 0);
}
byte[] dataArray = result_data[i];
if (dataArray == null) {
return PlotBlock.get(id, 0);
}
return PlotBlock.get(id, dataArray[j]);
}
public int getX() {
return chunk == null ? cx : chunk.getX();
}
public int getZ() {
return chunk == null ? cz : chunk.getZ();
}
@Override
public String getWorld() {
return chunk == null ? world : chunk.getWorld().getName();
}
@Override
public Location getMax() {
return new Location(getWorld(), 15 + (getX() << 4), 255, 15 + (getZ() << 4));
}
@Override
public Location getMin() {
return new Location(getWorld(), getX() << 4, 0, getZ() << 4);
}
public GenChunk clone() {
GenChunk toReturn = new GenChunk(chunk, new ChunkWrapper(getWorld(), chunk.getX(), chunk.getZ()));
if (this.result != null) {
for (int i = 0; i < this.result.length; i++) {
short[] matrix = this.result[i];
if (matrix != null) {
toReturn.result[i] = new short[matrix.length];
System.arraycopy(matrix, 0, toReturn.result[i], 0, matrix.length);
}
}
for (int i = 0; i < this.result_data.length; i++) {
byte[] matrix = this.result_data[i];
if (matrix != null) {
toReturn.result_data[i] = new byte[matrix.length];
System.arraycopy(matrix, 0, toReturn.result_data[i], 0, matrix.length);
}
}
}
toReturn.cd = this.cd;
return toReturn;
}
public GenChunk shallowClone() {
GenChunk toReturn = new GenChunk(chunk, new ChunkWrapper(getWorld(), getX(), getZ()));
toReturn.result = this.result;
toReturn.result_data = this.result_data;
toReturn.cd = this.cd;
return toReturn;
}
}

View File

@ -0,0 +1,12 @@
package com.plotsquared.bukkit.uuid;
import java.io.File;
import java.io.FilenameFilter;
public class DatFileFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".dat");
}
}

View File

@ -1,41 +1,41 @@
package com.plotsquared.bukkit.uuid; package com.plotsquared.bukkit.uuid;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import com.intellectualcrafters.plot.object.OfflinePlotPlayer; import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.uuid.UUIDWrapper; import com.intellectualcrafters.plot.uuid.UUIDWrapper;
import com.plotsquared.bukkit.object.BukkitOfflinePlayer; import com.plotsquared.bukkit.object.BukkitOfflinePlayer;
import com.plotsquared.bukkit.object.BukkitPlayer; import com.plotsquared.bukkit.object.BukkitPlayer;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import java.util.UUID;
public class DefaultUUIDWrapper extends UUIDWrapper { public class DefaultUUIDWrapper extends UUIDWrapper {
@Override @Override
public UUID getUUID(final PlotPlayer player) { public UUID getUUID(PlotPlayer player) {
return ((BukkitPlayer) player).player.getUniqueId(); return ((BukkitPlayer) player).player.getUniqueId();
} }
@Override @Override
public UUID getUUID(final OfflinePlotPlayer player) { public UUID getUUID(OfflinePlotPlayer player) {
return player.getUUID(); return player.getUUID();
} }
@Override @Override
public OfflinePlotPlayer getOfflinePlayer(final UUID uuid) { public OfflinePlotPlayer getOfflinePlayer(UUID uuid) {
return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(uuid)); return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(uuid));
} }
@Override @Override
public UUID getUUID(final String name) { public UUID getUUID(String name) {
return Bukkit.getOfflinePlayer(name).getUniqueId(); return Bukkit.getOfflinePlayer(name).getUniqueId();
} }
@Override @Override
public OfflinePlotPlayer[] getOfflinePlayers() { public OfflinePlotPlayer[] getOfflinePlayers() {
final OfflinePlayer[] ops = Bukkit.getOfflinePlayers(); OfflinePlayer[] ops = Bukkit.getOfflinePlayers();
final BukkitOfflinePlayer[] toReturn = new BukkitOfflinePlayer[ops.length]; BukkitOfflinePlayer[] toReturn = new BukkitOfflinePlayer[ops.length];
for (int i = 0; i < ops.length; i++) { for (int i = 0; i < ops.length; i++) {
toReturn[i] = new BukkitOfflinePlayer(ops[i]); toReturn[i] = new BukkitOfflinePlayer(ops[i]);
} }

View File

@ -0,0 +1,231 @@
package com.plotsquared.bukkit.uuid;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
import com.intellectualcrafters.plot.object.RunnableVal;
import com.intellectualcrafters.plot.object.StringWrapper;
import com.intellectualcrafters.plot.util.StringMan;
import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.UUIDHandler;
import com.intellectualcrafters.plot.util.UUIDHandlerImplementation;
import com.intellectualcrafters.plot.util.expiry.ExpireManager;
import com.intellectualcrafters.plot.uuid.UUIDWrapper;
import com.plotsquared.bukkit.util.NbtFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.World;
public class FileUUIDHandler extends UUIDHandlerImplementation {
public FileUUIDHandler(UUIDWrapper wrapper) {
super(wrapper);
}
@Override
public boolean startCaching(Runnable whenDone) {
return super.startCaching(whenDone) && cache(whenDone);
}
public boolean cache(final Runnable whenDone) {
final File container = Bukkit.getWorldContainer();
List<World> worlds = Bukkit.getWorlds();
final String world;
if (worlds.isEmpty()) {
world = "world";
} else {
world = worlds.get(0).getName();
}
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
PS.debug(C.PREFIX + "&6Starting player data caching for: " + world);
File uuidFile = new File(PS.get().IMP.getDirectory(), "uuids.txt");
if (uuidFile.exists()) {
try {
List<String> lines = Files.readAllLines(uuidFile.toPath(), StandardCharsets.UTF_8);
for (String line : lines) {
try {
line = line.trim();
if (line.isEmpty()) {
continue;
}
line = line.replaceAll("[\\|][0-9]+[\\|][0-9]+[\\|]", "");
String[] split = line.split("\\|");
String name = split[0];
if (name.isEmpty() || (name.length() > 16) || !StringMan.isAlphanumericUnd(name)) {
continue;
}
UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name);
if (uuid == null) {
continue;
}
UUIDHandler.add(new StringWrapper(name), uuid);
} catch (Exception e2) {
e2.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
HashBiMap<StringWrapper, UUID> toAdd = HashBiMap.create(new HashMap<StringWrapper, UUID>());
if (Settings.UUID.NATIVE_UUID_PROVIDER) {
HashSet<UUID> all = UUIDHandler.getAllUUIDS();
PS.debug("&aFast mode UUID caching enabled!");
File playerDataFolder = new File(container, world + File.separator + "playerdata");
String[] dat = playerDataFolder.list(new DatFileFilter());
boolean check = all.isEmpty();
if (dat != null) {
for (String current : dat) {
String s = current.replaceAll(".dat$", "");
try {
UUID uuid = UUID.fromString(s);
if (check || all.remove(uuid)) {
File file = new File(playerDataFolder, current);
NbtFactory.NbtCompound compound = NbtFactory.fromStream(new FileInputStream(file), NbtFactory.StreamOptions.GZIP_COMPRESSION);
if (!compound.containsKey("bukkit")) {
PS.debug("ERROR: Player data (" + uuid.toString() + ".dat) does not contain the the key \"bukkit\"");
} else {
NbtFactory.NbtCompound bukkit = (NbtFactory.NbtCompound) compound.get("bukkit");
String name = (String) bukkit.get("lastKnownName");
long last = (long) bukkit.get("lastPlayed");
if (ExpireManager.IMP != null) {
ExpireManager.IMP.storeDate(uuid, last);
}
toAdd.put(new StringWrapper(name), uuid);
}
}
} catch (Exception e) {
e.printStackTrace();
PS.debug(C.PREFIX + "Invalid playerdata: " + current);
}
}
}
add(toAdd);
if (all.isEmpty()) {
if (whenDone != null) {
whenDone.run();
}
return;
} else {
PS.debug("Failed to cache: " + all.size() + " uuids - slowly processing all files");
}
}
HashSet<String> worlds = Sets.newHashSet(world, "world");
HashSet<UUID> uuids = new HashSet<>();
HashSet<String> names = new HashSet<>();
File playerDataFolder = null;
for (String worldName : worlds) {
// Getting UUIDs
playerDataFolder = new File(container, worldName + File.separator + "playerdata");
String[] dat = playerDataFolder.list(new DatFileFilter());
if ((dat != null) && (dat.length != 0)) {
for (String current : dat) {
String s = current.replaceAll(".dat$", "");
try {
UUID uuid = UUID.fromString(s);
uuids.add(uuid);
} catch (Exception ignored) {
PS.debug(C.PREFIX + "Invalid PlayerData: " + current);
}
}
break;
}
// Getting names
File playersFolder = new File(worldName + File.separator + "players");
dat = playersFolder.list(new DatFileFilter());
if ((dat != null) && (dat.length != 0)) {
for (String current : dat) {
names.add(current.replaceAll(".dat$", ""));
}
break;
}
}
for (UUID uuid : uuids) {
try {
File file = new File(playerDataFolder + File.separator + uuid.toString() + ".dat");
if (!file.exists()) {
continue;
}
NbtFactory.NbtCompound compound = NbtFactory.fromStream(new FileInputStream(file), NbtFactory.StreamOptions.GZIP_COMPRESSION);
if (!compound.containsKey("bukkit")) {
PS.debug("ERROR: Player data (" + uuid.toString() + ".dat) does not contain the the key \"bukkit\"");
} else {
NbtFactory.NbtCompound bukkit = (NbtFactory.NbtCompound) compound.get("bukkit");
String name = (String) bukkit.get("lastKnownName");
StringWrapper wrap = new StringWrapper(name);
if (!toAdd.containsKey(wrap)) {
long last = (long) bukkit.get("lastPlayed");
if (Settings.UUID.OFFLINE) {
if (Settings.UUID.FORCE_LOWERCASE && !name.toLowerCase().equals(name)) {
uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name);
} else {
long most = (long) compound.get("UUIDMost");
long least = (long) compound.get("UUIDLeast");
uuid = new UUID(most, least);
}
}
if (ExpireManager.IMP != null) {
ExpireManager.IMP.storeDate(uuid, last);
}
toAdd.put(wrap, uuid);
}
}
} catch (Exception ignored) {
PS.debug(C.PREFIX + "&6Invalid PlayerData: " + uuid.toString() + ".dat");
}
}
for (String name : names) {
UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name);
StringWrapper nameWrap = new StringWrapper(name);
toAdd.put(nameWrap, uuid);
}
if (getUUIDMap().isEmpty()) {
for (OfflinePlotPlayer op : FileUUIDHandler.this.uuidWrapper.getOfflinePlayers()) {
long last = op.getLastPlayed();
if (last != 0) {
String name = op.getName();
StringWrapper wrap = new StringWrapper(name);
if (!toAdd.containsKey(wrap)) {
UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(op);
toAdd.put(wrap, uuid);
if (ExpireManager.IMP != null) {
ExpireManager.IMP.storeDate(uuid, last);
}
}
}
}
}
add(toAdd);
if (whenDone != null) {
whenDone.run();
}
}
});
return true;
}
@Override
public void fetchUUID(final String name, final RunnableVal<UUID> ifFetch) {
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
ifFetch.value = FileUUIDHandler.this.uuidWrapper.getUUID(name);
TaskManager.runTask(ifFetch);
}
});
}
}

View File

@ -0,0 +1,32 @@
package com.plotsquared.bukkit.uuid;
import com.google.common.base.Charsets;
import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
import com.intellectualcrafters.plot.object.PlotPlayer;
import org.bukkit.OfflinePlayer;
import java.util.UUID;
public class LowerOfflineUUIDWrapper extends OfflineUUIDWrapper {
@Override
public UUID getUUID(PlotPlayer player) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8));
}
@Override
public UUID getUUID(OfflinePlotPlayer player) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8));
}
@Override
public UUID getUUID(OfflinePlayer player) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8));
}
@Override
public UUID getUUID(String name) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name.toLowerCase()).getBytes(Charsets.UTF_8));
}
}

View File

@ -1,14 +1,5 @@
package com.plotsquared.bukkit.uuid; package com.plotsquared.bukkit.uuid;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;
@ -18,49 +9,57 @@ import com.intellectualcrafters.plot.object.StringWrapper;
import com.intellectualcrafters.plot.util.UUIDHandler; import com.intellectualcrafters.plot.util.UUIDHandler;
import com.intellectualcrafters.plot.uuid.UUIDWrapper; import com.intellectualcrafters.plot.uuid.UUIDWrapper;
import com.plotsquared.bukkit.object.BukkitOfflinePlayer; import com.plotsquared.bukkit.object.BukkitOfflinePlayer;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.UUID;
public class OfflineUUIDWrapper extends UUIDWrapper { public class OfflineUUIDWrapper extends UUIDWrapper {
private Method getOnline = null;
private final Object[] arg = new Object[0]; private final Object[] arg = new Object[0];
private Method getOnline = null;
public OfflineUUIDWrapper() { public OfflineUUIDWrapper() {
try { try {
getOnline = Server.class.getMethod("getOnlinePlayers"); this.getOnline = Server.class.getMethod("getOnlinePlayers");
} catch (final NoSuchMethodException | SecurityException e) { } catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
@Override @Override
public UUID getUUID(final PlotPlayer player) { public UUID getUUID(PlotPlayer player) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8)); return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8));
} }
@Override @Override
public UUID getUUID(final OfflinePlotPlayer player) { public UUID getUUID(OfflinePlotPlayer player) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8)); return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8));
} }
public UUID getUUID(final OfflinePlayer player) { public UUID getUUID(OfflinePlayer player) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8)); return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8));
} }
@Override @Override
public OfflinePlotPlayer getOfflinePlayer(final UUID uuid) { public OfflinePlotPlayer getOfflinePlayer(UUID uuid) {
final BiMap<UUID, StringWrapper> map = UUIDHandler.getUuidMap().inverse(); BiMap<UUID, StringWrapper> map = UUIDHandler.getUuidMap().inverse();
String name; String name = null;
try { if (map.containsKey(uuid)) {
name = map.get(uuid).value; name = map.get(uuid).value;
} catch (final NullPointerException e) {
name = null;
} }
if (name != null) { if (name != null) {
final OfflinePlayer op = Bukkit.getOfflinePlayer(name); OfflinePlayer op = Bukkit.getOfflinePlayer(name);
if (op.hasPlayedBefore()) { if (op.hasPlayedBefore()) {
return new BukkitOfflinePlayer(op); return new BukkitOfflinePlayer(op);
} }
} }
for (final OfflinePlayer player : Bukkit.getOfflinePlayers()) { for (OfflinePlayer player : Bukkit.getOfflinePlayers()) {
if (getUUID(player).equals(uuid)) { if (getUUID(player).equals(uuid)) {
return new BukkitOfflinePlayer(player); return new BukkitOfflinePlayer(player);
} }
@ -69,36 +68,35 @@ public class OfflineUUIDWrapper extends UUIDWrapper {
} }
public Player[] getOnlinePlayers() { public Player[] getOnlinePlayers() {
if (getOnline == null) { if (this.getOnline == null) {
Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers(); Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers();
return onlinePlayers.toArray(new Player[onlinePlayers.size()]); return onlinePlayers.toArray(new Player[onlinePlayers.size()]);
} }
try { try {
final Object players = getOnline.invoke(Bukkit.getServer(), arg); Object players = this.getOnline.invoke(Bukkit.getServer(), this.arg);
if (players instanceof Player[]) { if (players instanceof Player[]) {
return (Player[]) players; return (Player[]) players;
} else { } else {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked") Collection<? extends Player> p = (Collection<? extends Player>) players;
final Collection<? extends Player> p = (Collection<? extends Player>) players;
return p.toArray(new Player[p.size()]); return p.toArray(new Player[p.size()]);
} }
} catch (final Exception e) { } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ignored) {
PS.debug("Failed to resolve online players"); PS.debug("Failed to resolve online players");
getOnline = null; this.getOnline = null;
Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers(); Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers();
return onlinePlayers.toArray(new Player[onlinePlayers.size()]); return onlinePlayers.toArray(new Player[onlinePlayers.size()]);
} }
} }
@Override @Override
public UUID getUUID(final String name) { public UUID getUUID(String name) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)); return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8));
} }
@Override @Override
public OfflinePlotPlayer[] getOfflinePlayers() { public OfflinePlotPlayer[] getOfflinePlayers() {
final OfflinePlayer[] ops = Bukkit.getOfflinePlayers(); OfflinePlayer[] ops = Bukkit.getOfflinePlayers();
final BukkitOfflinePlayer[] toReturn = new BukkitOfflinePlayer[ops.length]; BukkitOfflinePlayer[] toReturn = new BukkitOfflinePlayer[ops.length];
for (int i = 0; i < ops.length; i++) { for (int i = 0; i < ops.length; i++) {
toReturn[i] = new BukkitOfflinePlayer(ops[i]); toReturn[i] = new BukkitOfflinePlayer(ops[i]);
} }

View File

@ -0,0 +1,248 @@
package com.plotsquared.bukkit.uuid;
import com.google.common.collect.HashBiMap;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.Settings;
import com.intellectualcrafters.plot.database.SQLite;
import com.intellectualcrafters.plot.object.RunnableVal;
import com.intellectualcrafters.plot.object.StringWrapper;
import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.UUIDHandler;
import com.intellectualcrafters.plot.util.UUIDHandlerImplementation;
import com.intellectualcrafters.plot.uuid.UUIDWrapper;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.HashMap;
import java.util.UUID;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class SQLUUIDHandler extends UUIDHandlerImplementation {
final int MAX_REQUESTS = 500;
private final String PROFILE_URL = "https://sessionserver.mojang.com/session/minecraft/profile/";
private final int INTERVAL = 12000;
private final JSONParser jsonParser = new JSONParser();
private final SQLite sqlite;
public SQLUUIDHandler(UUIDWrapper wrapper) {
super(wrapper);
this.sqlite = new SQLite(MainUtil.getFile(PS.get().IMP.getDirectory(), "usercache.db"));
try {
this.sqlite.openConnection();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
try (PreparedStatement stmt = getConnection().prepareStatement(
"CREATE TABLE IF NOT EXISTS `usercache` (uuid VARCHAR(32) NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY (uuid, username)"
+ ')')) {
stmt.execute();
} catch (SQLException e) {
e.printStackTrace();
}
startCaching(null);
}
private Connection getConnection() {
synchronized (this.sqlite) {
return this.sqlite.getConnection();
}
}
@Override
public boolean startCaching(final Runnable whenDone) {
if (!super.startCaching(whenDone)) {
return false;
}
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
try {
HashBiMap<StringWrapper, UUID> toAdd = HashBiMap.create(new HashMap<StringWrapper, UUID>());
try (PreparedStatement statement = getConnection().prepareStatement("SELECT `uuid`, `username` FROM `usercache`");
ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
StringWrapper username = new StringWrapper(resultSet.getString("username"));
UUID uuid = UUID.fromString(resultSet.getString("uuid"));
toAdd.put(new StringWrapper(username.value), uuid);
}
}
add(toAdd);
// This should be called as long as there are some unknown plots
final ArrayDeque<UUID> toFetch = new ArrayDeque<>();
for (UUID u : UUIDHandler.getAllUUIDS()) {
if (!uuidExists(u)) {
toFetch.add(u);
}
}
if (toFetch.isEmpty()) {
if (whenDone != null) {
whenDone.run();
}
return;
}
FileUUIDHandler fileHandler = new FileUUIDHandler(SQLUUIDHandler.this.uuidWrapper);
fileHandler.startCaching(new Runnable() {
@Override
public void run() {
// If the file based UUID handler didn't cache it, then we can't cache offline mode
// Also, trying to cache based on files again, is useless as that's what the file based uuid cacher does
if (Settings.UUID.OFFLINE) {
if (whenDone != null) {
whenDone.run();
}
return;
}
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
try {
if (toFetch.isEmpty()) {
if (whenDone != null) {
whenDone.run();
}
return;
}
for (int i = 0; i < Math.min(500, toFetch.size()); i++) {
UUID uuid = toFetch.pop();
HttpURLConnection connection =
(HttpURLConnection) new URL(SQLUUIDHandler.this.PROFILE_URL + uuid.toString().replace("-", ""))
.openConnection();
try (InputStream con = connection.getInputStream()) {
InputStreamReader reader = new InputStreamReader(con);
JSONObject response = (JSONObject) SQLUUIDHandler.this.jsonParser.parse(reader);
String name = (String) response.get("name");
if (name != null) {
add(new StringWrapper(name), uuid);
}
}
}
} catch (IOException | ParseException e) {
PS.debug("Invalid response from Mojang: Some UUIDs will be cached later. (`unknown` until then or player joins)");
}
TaskManager.runTaskLaterAsync(this, SQLUUIDHandler.this.INTERVAL);
}
});
}
});
} catch (SQLException e) {
throw new SQLUUIDHandlerException("Couldn't select :s", e);
}
}
});
return true;
}
@Override
public void fetchUUID(final String name, final RunnableVal<UUID> ifFetch) {
PS.debug(C.PREFIX + "UUID for '" + name + "' was null. We'll cache this from the Mojang servers!");
if (ifFetch == null) {
return;
}
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
try {
URL url = new URL(SQLUUIDHandler.this.PROFILE_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
String body = JSONArray.toJSONString(Collections.singletonList(name));
OutputStream stream = connection.getOutputStream();
stream.write(body.getBytes());
stream.flush();
stream.close();
JSONArray array = (JSONArray) SQLUUIDHandler.this.jsonParser.parse(new InputStreamReader(connection.getInputStream()));
JSONObject jsonProfile = (JSONObject) array.get(0);
String id = (String) jsonProfile.get("id");
String name = (String) jsonProfile.get("name");
ifFetch.value = UUID.fromString(
id.substring(0, 8) + '-' + id.substring(8, 12) + '-' + id.substring(12, 16) + '-' + id.substring(16, 20) + '-' + id
.substring(20, 32));
} catch (IOException | ParseException e) {
e.printStackTrace();
}
TaskManager.runTask(ifFetch);
}
});
}
@Override
public void handleShutdown() {
super.handleShutdown();
try {
getConnection().close();
} catch (SQLException e) {
throw new SQLUUIDHandlerException("Couldn't close database connection", e);
}
}
@Override
public boolean add(final StringWrapper name, final UUID uuid) {
// Ignoring duplicates
if (super.add(name, uuid)) {
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
try (PreparedStatement statement = getConnection().prepareStatement("REPLACE INTO usercache (`uuid`, `username`) VALUES(?, ?)")) {
statement.setString(1, uuid.toString());
statement.setString(2, name.toString());
statement.execute();
PS.debug(C.PREFIX + "&cAdded '&6" + uuid + "&c' - '&6" + name + "&c'");
} catch (SQLException e) {
e.printStackTrace();
}
}
});
return true;
}
return false;
}
/**
* This is useful for name changes
*/
@Override
public void rename(final UUID uuid, final StringWrapper name) {
super.rename(uuid, name);
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
try (PreparedStatement statement = getConnection().prepareStatement("UPDATE usercache SET `username`=? WHERE `uuid`=?")) {
statement.setString(1, name.value);
statement.setString(2, uuid.toString());
statement.execute();
PS.debug(C.PREFIX + "Name change for '" + uuid + "' to '" + name.value + '\'');
} catch (SQLException e) {
e.printStackTrace();
}
}
});
}
private class SQLUUIDHandlerException extends RuntimeException {
SQLUUIDHandlerException(String s, Throwable c) {
super("SQLUUIDHandler caused an exception: " + s, c);
}
}
}

View File

@ -0,0 +1,313 @@
name: ${name}
main: com.plotsquared.bukkit.BukkitMain
version: ${version}
load: STARTUP
description: >
Easy, yet powerful Plot World generation and management.
authors: [Citymonstret, Empire92, MattBDev]
softdepend: [WorldEdit, BarAPI, CameraAPI, Vault]
loadbefore: [MultiWorld, Multiverse-Core]
database: false
commands:
plots:
description: Plot command.
aliases: [p,plot,ps,plotsquared,p2,2,plotme]
permission: plots.use
permission-message: "You are lacking the permission node 'plots.use'"
permissions:
plots.use:
default: true
plots.permpack.basicflags:
default: op
children:
plots.set.flag: true
plots.flag: true
plots.flag.add: true
plots.flag.remove: true
plots.flag.list: true
plots.flag.info: true
plots.set.flag.titles.*: true
plots.set.flag.greeting.*: true
plots.set.flag.farewell.*: true
plots.set.flag.notify-enter.*: true
plots.set.flag.notify-leave.*: true
plots.set.flag.feed.*: true
plots.set.flag.heal.*: true
plots.set.flag.invincible.*: true
plots.set.flag.instabreak.*: true
plots.set.flag.fly.*: true
plots.set.flag.gamemode: true
plots.set.flag.gamemode.creative: true
plots.set.flag.gamemode.survival: true
plots.set.flag.gamemode.adventure: true
plots.set.flag.time.*: true
plots.set.flag.weather.*: true
plots.set.flag.music.*: true
plots.set.flag.disable-physics.*: true
plots.set.flag.pve.*: true
plots.set.flag.pvp.*: true
plots.set.flag.explosion.*: true
plots.set.flag.hostile-interact.*: true
plots.set.flag.hostile-attack.*: true
plots.set.flag.player-interact.*: true
plots.set.flag.animal-interact.*: true
plots.set.flag.animal-attack.*: true
plots.set.flag.tamed-interact.*: true
plots.set.flag.tamed-attack.*: true
plots.set.flag.misc-interact.*: true
plots.set.flag.hanging-place.*: true
plots.set.flag.hanging-break.*: true
plots.set.flag.vehicle-use.*: true
plots.set.flag.vehicle-place.*: true
plots.set.flag.vehicle-break.*: true
plots.set.flag.player-interact.*: true
plots.set.flag.place.*: true
plots.set.flag.break.*: true
plots.set.flag.use.*: true
plots.set.flag.forcefield.*: true
plots.set.flag.price.*: true
plots.set.flag.no-worldedit.*: true
plots.permpack.basicinbox:
default: op
children:
comments.notifications.enabled : true
plots.inbox.read.public: true
plots.inbox.modify.public: true
plots.inbox.modify.public: true
plots.inbox.write.public: true
plots.inbox.read.public: true
plots.inbox.read.report: true
plots.inbox.write.report: true
plots.inbox.read.report: true
plots.inbox.read.owner: true
plots.inbox.modify.owner: true
plots.inbox.write.owner: true
plots.inbox.read.owner: true
plots.comment: true
plots.inbox: true
plots.permpack.wilderness:
default: op
children:
plots.admin.interact.unowned: true
plots.admin.destroy.unowned: true
plots.admin.build.unowned: true
plots.projectile.unowned: true
plots.admin.vehicle.break.unowned: true
plots.admin.pve.unowned: true
plots.permpack.basic:
default: op
children:
plots.use: true
plots.info: true
plots.claim: true
plots.auto: true
plots.home: true
plots.clear: true
plots.delete: true
plots.music: true
plots.list: true
plots.list.mine: true
plots.list.shared: true
plots.list.world: true
plots.list.all: true
plots.list.forsale: true
plots.list.unowned: true
plots.list.unknown: true
plots.set: true
plots.visit: true
plots.visit.owned: true
plots.visit.shared: true
plots.set.flag: true
plots.flag.add: true
plots.flag.remove: true
plots.flag.list: true
plots.flag.info: true
plots.flag: true
plots.buy: true
plots.chat: true
plots.confirm: true
plots.toggle: true
plots.toggle.titles: true
plots.toggle.chat: true
plots.set.biome: true
plots.set.home: true
plots.set.alias: true
plots.set.description: true
plots.description: true
plots.alias: true
plots.merge: true
plots.merge.other: true
plots.merge.4: true
plots.unlink: true
plots.denied: true
plots.add: true
plots.trust: true
plots.deny: true
plots.remove: true
plots.untrust: true
plots.undeny: true
plots.kick: true
plots.download: true
plots.save: true
plots.done: true
plots.continue: true
plots.middle: true
plots.worldedit.bypass:
default: false
plots.gamemode.bypass:
default: op
plots.confirm.bypass:
default: false
plotme.use:
description: Gives default user commands
children:
plots.permpack.basic: true
plots.plot.1: true
plotme.admin:
description: Gives default administrator commands
children:
plots.admin: true
plotme.use.middle:
children:
plots.middle: true
plotme.use.buy:
children:
plots.buy: true
plotme.use.sell:
children:
plots.set: true
plots.flag: true
plots.set.flag: true
plots.set.price.*: true
plotme.use.dispose:
children:
plots.delete: true
plotme.use.done:
children:
plots.done: true
plotme.use.claim:
children:
plots.claim: true
plotme.use.auto:
children:
plots.auto: true
plotme.use.reset:
children:
plots.delete: true
plotme.use.home:
children:
plots.home: true
plotme.use.info:
children:
plots.info: true
plotme.use.biome:
children:
plots.set: true
plots.set.biome: true
plotme.use.clear:
children:
plots.clear: true
plotme.use.list:
children:
plots.list: true
plots.list.forsale: true
plots.list.mine: true
plots.list.shared: true
plotme.use.add:
children:
plots.add: true
plots.trust: true
plots.add.everyone: true
plots.trust.everyone: true
plotme.use.deny:
children:
plots.deny: true
plots.deny.everyone: true
plotme.use.remove:
children:
plots.remove: true
plotme.use.undeny:
children:
plots.remove: true
plotme.use.protect:
children:
plots.set: true
plots.flag: true
plots.set.flag: true
plots.set.keep.*: true
plotme.use.nameplot:
children:
plots.set.alias: true
plotme.limit.*:
children:
plots.plot.*: true
plotme.limit.1:
children:
plots.plot.1: true
plotme.limit.5:
children:
plots.plot.5: true
plotme.limit.10:
children:
plots.plot.10: true
plotme.admin.home.other:
children:
plots.plot.: true
plotme.admin.clear:
children:
plots.admin.command.clear: true
plotme.admin.reset:
children:
plots.admin.command.delete: true
plotme.admin.add:
children:
plots.admin.command.add: true
plotme.admin.deny:
children:
plots.admin.command.deny: true
plotme.admin.remove:
children:
plots.admin.command.remove: true
plotme.admin.undeny:
children:
plots.admin.command.remove: true
plotme.admin.bypassdeny:
children:
plots.admin.entry.denied: true
plotme.admin.setowner:
children:
plots.admin.command.setowner: true
plotme.admin.move:
children:
plots.admin.command.move: true
plotme.admin.weanywhere:
children:
plots.worldedit.bypass: true
plotme.admin.list:
children:
plots.list.world: true
plots.list.world.*: true
plots.list.top: true
plots.list.all: true
plots.list.unowned: true
plots.list.unknown: true
plots.list.player: true
plots.list.done: true
plots.list.expired: true
plots.list.fuzzy: true
plots.list.area: true
plotme.admin.dispose:
children:
plots.admin.command.delete: true
plotme.admin.done:
children:
plots.admin.command.done: true
plotme.admin.expired:
children:
plots.list.expired: true
plotme.admin.buildanywhere:
children:
plots.admin.vehicle.*: true
plots.admin.interact.*: true
plots.admin.build.*: true
plots.admin.destroy.*: true

52
Core/build.gradle Normal file
View File

@ -0,0 +1,52 @@
dependencies {
testCompile 'junit:junit:4.12'
compile 'org.yaml:snakeyaml:1.16'
compile 'com.google.code.gson:gson:2.2.4'
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
processResources {
from('src/main/resources') {
include 'plugin.properties'
expand(
version: "${project.parent.version}",
name: project.parent.name,
)
}
}
jar.archiveName="plotsquared-api-${project.parent.version}.jar"
jar.destinationDir = file '../mvn/com/plotsquared/plotsquared-api/' + project.parent.version
task createPom << {
pom {
project {
groupId 'com.plotsquared'
artifactId 'plotsquared-api'
version project.parent.version
}
}.writeTo("../mvn/com/plotsquared/plotsquared-api/${project.parent.version}/plotsquared-api-${project.parent.version}.pom")
pom {
project {
groupId 'com.plotsquared'
artifactId 'plotsquared-api'
version 'latest'
}
}.writeTo("../mvn/com/plotsquared/plotsquared-api/latest/plotsquared-api-latest.pom")
}
task copyFiles {
doLast {
copy {
from "../mvn/com/plotsquared/plotsquared-api/${project.parent.version}/"
into '../mvn/com/plotsquared/plotsquared-api/latest/'
include('*.jar')
rename ("plotsquared-api-${project.parent.version}.jar", 'plotsquared-api-latest.jar')
}
}
}
build.finalizedBy(copyFiles)
copyFiles.dependsOn(createPom)

View File

@ -3,83 +3,84 @@ package com.intellectualcrafters.configuration;
import java.util.Map; import java.util.Map;
/** /**
* Represents a source of configurable options and settings * Represents a source of configurable options and settings.
*/ */
public interface Configuration extends ConfigurationSection { public interface Configuration extends ConfigurationSection {
/** /**
* Sets the default value of the given path as provided. * Sets the default value of the given path as provided.
* <p> *
* If no source {@link Configuration} was provided as a default * <p>If no source {@link Configuration} was provided as a default
* collection, then a new {@link MemoryConfiguration} will be created to * collection, then a new {@link MemoryConfiguration} will be created to
* hold the new default value. * hold the new default value.</p>
* <p> *
* If value is null, the value will be removed from the default * <p>If value is null, the value will be removed from the default
* Configuration source. * Configuration source.</p>
* *
* @param path Path of the value to set. * @param path Path of the value to set.
* @param value Value to set the default to. * @param value Value to set the default to.
* @throws IllegalArgumentException Thrown if path is null. * @throws IllegalArgumentException Thrown if path is null.
*/ */
@Override @Override void addDefault(String path, Object value);
public void addDefault(final String path, final Object value);
/** /**
* Sets the default values of the given paths as provided. * Sets the default values of the given paths as provided.
* <p> *
* If no source {@link Configuration} was provided as a default * <p>If no source {@link Configuration} was provided as a default
* collection, then a new {@link MemoryConfiguration} will be created to * collection, then a new {@link MemoryConfiguration} will be created to
* hold the new default values. * hold the new default values.</p>
* *
* @param defaults A map of Path->Values to add to defaults. * @param defaults A map of Path->Values to add to defaults.
* @throws IllegalArgumentException Thrown if defaults is null. * @throws IllegalArgumentException Thrown if defaults is null.
*/ */
public void addDefaults(final Map<String, Object> defaults); void addDefaults(Map<String, Object> defaults);
/** /**
* Sets the default values of the given paths as provided. * Sets the default values of the given paths as provided.
* <p> *
* If no source {@link Configuration} was provided as a default * <p>If no source {@link Configuration} was provided as a default
* collection, then a new {@link MemoryConfiguration} will be created to * collection, then a new {@link MemoryConfiguration} will be created to
* hold the new default value. * hold the new default value.</p>
* <p> *
* This method will not hold a reference to the specified Configuration, * <p>This method will not hold a reference to the specified Configuration,
* nor will it automatically update if that Configuration ever changes. If * nor will it automatically update if that Configuration ever changes. If
* you require this, you should set the default source with {@link * you check this, you should set the default source with {@link
* #setDefaults(com.intellectualcrafters.configuration.Configuration)}. * #setDefaults(Configuration)}.</p>
* *
* @param defaults A configuration holding a list of defaults to copy. * @param defaults A configuration holding a list of defaults to copy.
* @throws IllegalArgumentException Thrown if defaults is null or this. * @throws IllegalArgumentException Thrown if defaults is null or this.
*/ */
public void addDefaults(final Configuration defaults); void addDefaults(Configuration defaults);
/**
* Gets the source {@link Configuration} for this configuration.
*
* <p>
* If no configuration source was set, but default values were added, then
* a {@link MemoryConfiguration} will be returned. If no source was set
* and no defaults were set, then this method will return null.</p>
*
* @return Configuration source for default values, or null if none exist.
*/
Configuration getDefaults();
/** /**
* Sets the source of all default values for this {@link Configuration}. * Sets the source of all default values for this {@link Configuration}.
*
* <p> * <p>
* If a previous source was set, or previous default values were defined, * If a previous source was set, or previous default values were defined,
* then they will not be copied to the new source. * then they will not be copied to the new source.</p>
* *
* @param defaults New source of default values for this configuration. * @param defaults New source of default values for this configuration.
* @throws IllegalArgumentException Thrown if defaults is null or this. * @throws IllegalArgumentException Thrown if defaults is null or this.
*/ */
public void setDefaults(final Configuration defaults); void setDefaults(Configuration defaults);
/**
* Gets the source {@link Configuration} for this configuration.
* <p>
* If no configuration source was set, but default values were added, then
* a {@link MemoryConfiguration} will be returned. If no source was set
* and no defaults were set, then this method will return null.
*
* @return Configuration source for default values, or null if none exist.
*/
public Configuration getDefaults();
/** /**
* Gets the {@link ConfigurationOptions} for this {@link Configuration}. * Gets the {@link ConfigurationOptions} for this {@link Configuration}.
* <p> *
* All setters through this method are chainable. * <p>All setters through this method are chainable.</p>
* *
* @return Options for this configuration * @return Options for this configuration
*/ */
public ConfigurationOptions options(); ConfigurationOptions options();
} }

View File

@ -2,14 +2,14 @@ package com.intellectualcrafters.configuration;
/** /**
* Various settings for controlling the input and output of a {@link * Various settings for controlling the input and output of a {@link
* Configuration} * Configuration}.
*/ */
public class ConfigurationOptions { class ConfigurationOptions {
private final Configuration configuration;
private char pathSeparator = '.'; private char pathSeparator = '.';
private boolean copyDefaults = false; private boolean copyDefaults = false;
private final Configuration configuration;
protected ConfigurationOptions(final Configuration configuration) { protected ConfigurationOptions(Configuration configuration) {
this.configuration = configuration; this.configuration = configuration;
} }
@ -24,9 +24,9 @@ public class ConfigurationOptions {
/** /**
* Gets the char that will be used to separate {@link * Gets the char that will be used to separate {@link
* ConfigurationSection}s * ConfigurationSection}s.
* <p> *
* This value does not affect how the {@link Configuration} is stored, * <p>This value does not affect how the {@link Configuration} is stored,
* only in how you access the data. The default value is '.'. * only in how you access the data. The default value is '.'.
* *
* @return Path separator * @return Path separator
@ -37,15 +37,15 @@ public class ConfigurationOptions {
/** /**
* Sets the char that will be used to separate {@link * Sets the char that will be used to separate {@link
* ConfigurationSection}s * ConfigurationSection}s.
* <p> *
* This value does not affect how the {@link Configuration} is stored, * <p>This value does not affect how the {@link Configuration} is stored,
* only in how you access the data. The default value is '.'. * only in how you access the data. The default value is '.'.
* *
* @param value Path separator * @param value Path separator
* @return This object, for chaining * @return This object, for chaining
*/ */
public ConfigurationOptions pathSeparator(final char value) { public ConfigurationOptions pathSeparator(char value) {
pathSeparator = value; pathSeparator = value;
return this; return this;
} }
@ -53,13 +53,13 @@ public class ConfigurationOptions {
/** /**
* Checks if the {@link Configuration} should copy values from its default * Checks if the {@link Configuration} should copy values from its default
* {@link Configuration} directly. * {@link Configuration} directly.
* <p> *
* If this is true, all values in the default Configuration will be * <p>If this is true, all values in the default Configuration will be
* directly copied, making it impossible to distinguish between values * directly copied, making it impossible to distinguish between values
* that were set and values that are provided by default. As a result, * that were set and values that are provided by default. As a result,
* {@link ConfigurationSection#contains(java.lang.String)} will always * {@link ConfigurationSection#contains(String)} will always
* return the same value as {@link * return the same value as {@link
* ConfigurationSection#isSet(java.lang.String)}. The default value is * ConfigurationSection#isSet(String)}. The default value is
* false. * false.
* *
* @return Whether or not defaults are directly copied * @return Whether or not defaults are directly copied
@ -71,19 +71,19 @@ public class ConfigurationOptions {
/** /**
* Sets if the {@link Configuration} should copy values from its default * Sets if the {@link Configuration} should copy values from its default
* {@link Configuration} directly. * {@link Configuration} directly.
* <p> *
* If this is true, all values in the default Configuration will be * <p>If this is true, all values in the default Configuration will be
* directly copied, making it impossible to distinguish between values * directly copied, making it impossible to distinguish between values
* that were set and values that are provided by default. As a result, * that were set and values that are provided by default. As a result,
* {@link ConfigurationSection#contains(java.lang.String)} will always * {@link ConfigurationSection#contains(String)} will always
* return the same value as {@link * return the same value as {@link
* ConfigurationSection#isSet(java.lang.String)}. The default value is * ConfigurationSection#isSet(String)}. The default value is
* false. * false.
* *
* @param value Whether or not defaults are directly copied * @param value Whether or not defaults are directly copied
* @return This object, for chaining * @return This object, for chaining
*/ */
public ConfigurationOptions copyDefaults(final boolean value) { public ConfigurationOptions copyDefaults(boolean value) {
copyDefaults = value; copyDefaults = value;
return this; return this;
} }

View File

@ -5,156 +5,161 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* Represents a section of a {@link Configuration} * Represents a section of a {@link Configuration}.
*/ */
public interface ConfigurationSection { public interface ConfigurationSection {
/** /**
* Gets a set containing all keys in this section. * Gets a set containing all keys in this section.
* <p> *
* If deep is set to true, then this will contain all the keys within any * <p>If deep is set to true, then this will contain all the keys within any
* child {@link ConfigurationSection}s (and their children, etc). These * child {@link ConfigurationSection}s (and their children, etc). These
* will be in a valid path notation for you to use. * will be in a valid path notation for you to use.
* <p> *
* If deep is set to false, then this will contain only the keys of any * <p>If deep is set to false, then this will contain only the keys of any
* direct children, and not their own children. * direct children, and not their own children.
* *
* @param deep Whether or not to get a deep list, as opposed to a shallow * @param deep Whether or not to get a deep list, as opposed to a shallow
* list. * list.
* @return Set of keys contained within this ConfigurationSection. * @return Set of keys contained within this ConfigurationSection.
*/ */
public Set<String> getKeys(final boolean deep); Set<String> getKeys(boolean deep);
/** /**
* Gets a Map containing all keys and their values for this section. * Gets a Map containing all keys and their values for this section.
* <p> *
* If deep is set to true, then this will contain all the keys and values * <p>If deep is set to true, then this will contain all the keys and values
* within any child {@link ConfigurationSection}s (and their children, * within any child {@link ConfigurationSection}s (and their children,
* etc). These keys will be in a valid path notation for you to use. * etc). These keys will be in a valid path notation for you to use.
* <p> *
* If deep is set to false, then this will contain only the keys and * <p>If deep is set to false, then this will contain only the keys and
* values of any direct children, and not their own children. * values of any direct children, and not their own children.
* *
* @param deep Whether or not to get a deep list, as opposed to a shallow * @param deep Whether or not to get a deep list, as opposed to a shallow
* list. * list.
* @return Map of keys and values of this section. * @return Map of keys and values of this section.
*/ */
public Map<String, Object> getValues(final boolean deep); Map<String, Object> getValues(boolean deep);
/** /**
* Checks if this {@link ConfigurationSection} contains the given path. * Checks if this {@link ConfigurationSection} contains the given path.
* <p> *
* If the value for the requested path does not exist but a default value * <p>If the value for the requested path does not exist but a default value
* has been specified, this will return true. * has been specified, this will return true.
* *
* @param path Path to check for existence. * @param path Path to check for existence.
* @return True if this section contains the requested path, either via * @return True if this section contains the requested path, either via
* default or being set. * default or being set.
* @throws IllegalArgumentException Thrown when path is null. * @throws IllegalArgumentException Thrown when path is {@code null}.
*/ */
public boolean contains(final String path); boolean contains(String path);
/** /**
* Checks if this {@link ConfigurationSection} has a value set for the * Checks if this {@link ConfigurationSection} has a value set for the
* given path. * given path.
* <p> *
* If the value for the requested path does not exist but a default value * <p>If the value for the requested path does not exist but a default value
* has been specified, this will still return false. * has been specified, this will still return false.
* *
* @param path Path to check for existence. * @param path Path to check for existence.
* @return True if this section contains the requested path, regardless of * @return True if this section contains the requested path, regardless of
* having a default. * having a default.
* @throws IllegalArgumentException Thrown when path is null. * @throws IllegalArgumentException Thrown when path is {@code null}.
*/ */
public boolean isSet(final String path); boolean isSet(String path);
/** /**
* Gets the path of this {@link ConfigurationSection} from its root {@link * Gets the path of this {@link ConfigurationSection} from its root {@link
* Configuration} * Configuration}.
* <p> *
* For any {@link Configuration} themselves, this will return an empty * <p>For any {@link Configuration} themselves, this will return an empty
* string. * string.
* <p> *
* If the section is no longer contained within its root for any reason, * <p>If the section is no longer contained within its root for any reason,
* such as being replaced with a different value, this may return null. * such as being replaced with a different value,
* <p> * this may return {@code null}.
* To retrieve the single name of this section, that is, the final part of *
* the path returned by this method, you may use {@link #getName()}. * <p>To retrieve the single name of this section, that is, the final part
* of the path returned by this method, you may use {@link #getName()}.
* *
* @return Path of this section relative to its root * @return Path of this section relative to its root
*/ */
public String getCurrentPath(); String getCurrentPath();
/** /**
* Gets the name of this individual {@link ConfigurationSection}, in the * Gets the name of this individual {@link ConfigurationSection}, in the
* path. * path.
* <p> *
* This will always be the final part of {@link #getCurrentPath()}, unless * <p>This will always be the final part of {@link #getCurrentPath()}, unless
* the section is orphaned. * the section is orphaned.
* *
* @return Name of this section * @return Name of this section
*/ */
public String getName(); String getName();
/** /**
* Gets the root {@link Configuration} that contains this {@link * Gets the root {@link Configuration} that contains this {@link
* ConfigurationSection} * ConfigurationSection}
* <p> *
* For any {@link Configuration} themselves, this will return its own * <p>For any {@link Configuration} themselves, this will return its own
* object. * object.
* <p> *
* If the section is no longer contained within its root for any reason, * <p>If the section is no longer contained within its root for any reason,
* such as being replaced with a different value, this may return null. * such as being replaced with a different value,
* this may return {@code null}.
* *
* @return Root configuration containing this section. * @return Root configuration containing this section.
*/ */
public Configuration getRoot(); Configuration getRoot();
/** /**
* Gets the parent {@link ConfigurationSection} that directly contains * Gets the parent {@link ConfigurationSection} that directly contains
* this {@link ConfigurationSection}. * this {@link ConfigurationSection}.
* <p> *
* For any {@link Configuration} themselves, this will return null. * <p>For any {@link Configuration} themselves, this will return
* <p> * {@code null}.
* If the section is no longer contained within its parent for any reason, *
* such as being replaced with a different value, this may return null. * <p>If the section is no longer contained within its parent for any
* reason, such as being replaced with a different value, this may
* return {@code null}.
* *
* @return Parent section containing this section. * @return Parent section containing this section.
*/ */
public ConfigurationSection getParent(); ConfigurationSection getParent();
/** /**
* Gets the requested Object by path. * Gets the requested Object by path.
* <p> *
* If the Object does not exist but a default value has been specified, * <p>If the Object does not exist but a default value has been specified,
* this will return the default value. If the Object does not exist and no * this will return the default value. If the Object does not exist and no
* default value was specified, this will return null. * default value was specified, this will return {@code null}.
* *
* @param path Path of the Object to get. * @param path Path of the Object to get.
* @return Requested Object. * @return Requested Object.
*/ */
public Object get(final String path); Object get(String path);
/** /**
* Gets the requested Object by path, returning a default value if not * Gets the requested Object by path, returning a default value if not
* found. * found.
* <p> *
* If the Object does not exist then the specified default value will * <p>If the Object does not exist then the specified default value will
* returned regardless of if a default has been identified in the root * returned regardless of if a default has been identified in the root
* {@link Configuration}. * {@link Configuration}.
* *
* @param path Path of the Object to get. * @param path Path of the Object to get.
* @param def The default value to return if the path is not found. * @param defaultValue The default value to return if the path is not found.
* @return Requested Object. * @return Requested Object.
*/ */
public Object get(final String path, final Object def); Object get(String path, Object defaultValue);
/** /**
* Sets the specified path to the given value. * Sets the specified path to the given value.
* <p> *
* If value is null, the entry will be removed. Any existing entry will be * <p>If value is {@code null}, the entry will be removed. Any
* replaced, regardless of what the new value is. * existing entry will be replaced, regardless of what the new value is.
* <p> *
* Some implementations may have limitations on what you may store. See * <p>Some implementations may have limitations on what you may store. See
* their individual javadoc for details. No implementations should allow * their individual javadoc for details. No implementations should allow
* you to store {@link Configuration}s or {@link ConfigurationSection}s, * you to store {@link Configuration}s or {@link ConfigurationSection}s,
* please use {@link #createSection(String)} for that. * please use {@link #createSection(String)} for that.
@ -162,25 +167,25 @@ public interface ConfigurationSection {
* @param path Path of the object to set. * @param path Path of the object to set.
* @param value New value to set the path to. * @param value New value to set the path to.
*/ */
public void set(final String path, final Object value); void set(String path, Object value);
/** /**
* Creates an empty {@link ConfigurationSection} at the specified path. * Creates an empty {@link ConfigurationSection} at the specified path.
* <p> *
* Any value that was previously set at this path will be overwritten. If * <p>Any value that was previously set at this path will be overwritten. If
* the previous value was itself a {@link ConfigurationSection}, it will * the previous value was itself a {@link ConfigurationSection}, it will
* be orphaned. * be orphaned.
* *
* @param path Path to create the section at. * @param path Path to create the section at.
* @return Newly created section * @return Newly created section
*/ */
public ConfigurationSection createSection(final String path); ConfigurationSection createSection(String path);
/** /**
* Creates a {@link ConfigurationSection} at the specified path, with * Creates a {@link ConfigurationSection} at the specified path, with
* specified values. * specified values.
* <p> *
* Any value that was previously set at this path will be overwritten. If * <p>Any value that was previously set at this path will be overwritten. If
* the previous value was itself a {@link ConfigurationSection}, it will * the previous value was itself a {@link ConfigurationSection}, it will
* be orphaned. * be orphaned.
* *
@ -188,26 +193,27 @@ public interface ConfigurationSection {
* @param map The values to used. * @param map The values to used.
* @return Newly created section * @return Newly created section
*/ */
public ConfigurationSection createSection(final String path, final Map<?, ?> map); ConfigurationSection createSection(String path, Map<?, ?> map);
// Primitives // Primitives
/** /**
* Gets the requested String by path. * Gets the requested String by path.
* <p> *
* If the String does not exist but a default value has been specified, * <p>If the String does not exist but a default value has been specified,
* this will return the default value. If the String does not exist and no * this will return the default value. If the String does not exist and no
* default value was specified, this will return null. * default value was specified, this will return {@code null}.
* *
* @param path Path of the String to get. * @param path Path of the String to get.
* @return Requested String. * @return Requested String.
*/ */
public String getString(final String path); String getString(String path);
/** /**
* Gets the requested String by path, returning a default value if not * Gets the requested String by path, returning a default value if not
* found. * found.
* <p> *
* If the String does not exist then the specified default value will * <p>If the String does not exist then the specified default value will
* returned regardless of if a default has been identified in the root * returned regardless of if a default has been identified in the root
* {@link Configuration}. * {@link Configuration}.
* *
@ -216,37 +222,37 @@ public interface ConfigurationSection {
* not a String. * not a String.
* @return Requested String. * @return Requested String.
*/ */
public String getString(final String path, final String def); String getString(String path, String def);
/** /**
* Checks if the specified path is a String. * Checks if the specified path is a String.
* <p> *
* If the path exists but is not a String, this will return false. If the * <p>If the path exists but is not a String, this will return false. If
* path does not exist, this will return false. If the path does not exist * the path does not exist, this will return false. If the path does not
* but a default value has been specified, this will check if that default * exist but a default value has been specified, this will check if that
* value is a String and return appropriately. * defaultvalue is a String and return appropriately.
* *
* @param path Path of the String to check. * @param path Path of the String to check.
* @return Whether or not the specified path is a String. * @return Whether or not the specified path is a String.
*/ */
public boolean isString(final String path); boolean isString(String path);
/** /**
* Gets the requested int by path. * Gets the requested int by path.
* <p> *
* If the int does not exist but a default value has been specified, this * <p>If the int does not exist but a default value has been specified, this
* will return the default value. If the int does not exist and no default * will return the default value. If the int does not exist and no default
* value was specified, this will return 0. * value was specified, this will return 0.
* *
* @param path Path of the int to get. * @param path Path of the int to get.
* @return Requested int. * @return Requested int.
*/ */
public int getInt(final String path); int getInt(String path);
/** /**
* Gets the requested int by path, returning a default value if not found. * Gets the requested int by path, returning a default value if not found.
* <p> *
* If the int does not exist then the specified default value will * <p>If the int does not exist then the specified default value will
* returned regardless of if a default has been identified in the root * returned regardless of if a default has been identified in the root
* {@link Configuration}. * {@link Configuration}.
* *
@ -255,12 +261,12 @@ public interface ConfigurationSection {
* not an int. * not an int.
* @return Requested int. * @return Requested int.
*/ */
public int getInt(final String path, final int def); int getInt(String path, int def);
/** /**
* Checks if the specified path is an int. * Checks if the specified path is an int.
* <p> *
* If the path exists but is not a int, this will return false. If the * <p>If the path exists but is not a int, this will return false. If the
* path does not exist, this will return false. If the path does not exist * path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default * but a default value has been specified, this will check if that default
* value is a int and return appropriately. * value is a int and return appropriately.
@ -268,39 +274,39 @@ public interface ConfigurationSection {
* @param path Path of the int to check. * @param path Path of the int to check.
* @return Whether or not the specified path is an int. * @return Whether or not the specified path is an int.
*/ */
public boolean isInt(final String path); boolean isInt(String path);
/** /**
* Gets the requested boolean by path. * Gets the requested boolean by path.
* <p> *
* If the boolean does not exist but a default value has been specified, * <p>If the boolean does not exist but a default value has been specified,
* this will return the default value. If the boolean does not exist and * this will return the default value. If the boolean does not exist and
* no default value was specified, this will return false. * no default value was specified, this will return false.
* *
* @param path Path of the boolean to get. * @param path Path of the boolean to get.
* @return Requested boolean. * @return Requested boolean.
*/ */
public boolean getBoolean(final String path); boolean getBoolean(String path);
/** /**
* Gets the requested boolean by path, returning a default value if not * Gets the requested boolean by path, returning a default value if not
* found. * found.
* <p> *
* If the boolean does not exist then the specified default value will * <p>If the boolean does not exist then the specified default value will
* returned regardless of if a default has been identified in the root * returned regardless of if a default has been identified in the root
* {@link Configuration}. * {@link Configuration}.
* *
* @param path Path of the boolean to get. * @param path Path of the boolean to get.
* @param def The default value to return if the path is not found or is * @param defaultValue The default value to return if the path is not found or is
* not a boolean. * not a boolean.
* @return Requested boolean. * @return Requested boolean.
*/ */
public boolean getBoolean(final String path, final boolean def); boolean getBoolean(String path, boolean defaultValue);
/** /**
* Checks if the specified path is a boolean. * Checks if the specified path is a boolean.
* <p> *
* If the path exists but is not a boolean, this will return false. If the * <p>If the path exists but is not a boolean, this will return false. If the
* path does not exist, this will return false. If the path does not exist * path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default * but a default value has been specified, this will check if that default
* value is a boolean and return appropriately. * value is a boolean and return appropriately.
@ -308,39 +314,39 @@ public interface ConfigurationSection {
* @param path Path of the boolean to check. * @param path Path of the boolean to check.
* @return Whether or not the specified path is a boolean. * @return Whether or not the specified path is a boolean.
*/ */
public boolean isBoolean(final String path); boolean isBoolean(String path);
/** /**
* Gets the requested double by path. * Gets the requested double by path.
* <p> *
* If the double does not exist but a default value has been specified, * <p>If the double does not exist but a default value has been specified,
* this will return the default value. If the double does not exist and no * this will return the default value. If the double does not exist and no
* default value was specified, this will return 0. * default value was specified, this will return 0.
* *
* @param path Path of the double to get. * @param path Path of the double to get.
* @return Requested double. * @return Requested double.
*/ */
public double getDouble(final String path); double getDouble(String path);
/** /**
* Gets the requested double by path, returning a default value if not * Gets the requested double by path, returning a default value if not
* found. * found.
* <p> *
* If the double does not exist then the specified default value will * <p>If the double does not exist then the specified default value will
* returned regardless of if a default has been identified in the root * returned regardless of if a default has been identified in the root
* {@link Configuration}. * {@link Configuration}.
* *
* @param path Path of the double to get. * @param path Path of the double to get.
* @param def The default value to return if the path is not found or is * @param defaultValue The default value to return if the path is not found or is
* not a double. * not a double.
* @return Requested double. * @return Requested double.
*/ */
public double getDouble(final String path, final double def); double getDouble(String path, double defaultValue);
/** /**
* Checks if the specified path is a double. * Checks if the specified path is a double.
* <p> *
* If the path exists but is not a double, this will return false. If the * <p>If the path exists but is not a double, this will return false. If the
* path does not exist, this will return false. If the path does not exist * path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default * but a default value has been specified, this will check if that default
* value is a double and return appropriately. * value is a double and return appropriately.
@ -348,25 +354,25 @@ public interface ConfigurationSection {
* @param path Path of the double to check. * @param path Path of the double to check.
* @return Whether or not the specified path is a double. * @return Whether or not the specified path is a double.
*/ */
public boolean isDouble(final String path); boolean isDouble(String path);
/** /**
* Gets the requested long by path. * Gets the requested long by path.
* <p> *
* If the long does not exist but a default value has been specified, this * <p>If the long does not exist but a default value has been specified, this
* will return the default value. If the long does not exist and no * will return the default value. If the long does not exist and no
* default value was specified, this will return 0. * default value was specified, this will return 0.
* *
* @param path Path of the long to get. * @param path Path of the long to get.
* @return Requested long. * @return Requested long.
*/ */
public long getLong(final String path); long getLong(String path);
/** /**
* Gets the requested long by path, returning a default value if not * Gets the requested long by path, returning a default value if not
* found. * found.
* <p> *
* If the long does not exist then the specified default value will * <p>If the long does not exist then the specified default value will
* returned regardless of if a default has been identified in the root * returned regardless of if a default has been identified in the root
* {@link Configuration}. * {@link Configuration}.
* *
@ -375,12 +381,12 @@ public interface ConfigurationSection {
* not a long. * not a long.
* @return Requested long. * @return Requested long.
*/ */
public long getLong(final String path, final long def); long getLong(String path, long def);
/** /**
* Checks if the specified path is a long. * Checks if the specified path is a long.
* <p> *
* If the path exists but is not a long, this will return false. If the * <p>If the path exists but is not a long, this will return false. If the
* path does not exist, this will return false. If the path does not exist * path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default * but a default value has been specified, this will check if that default
* value is a long and return appropriately. * value is a long and return appropriately.
@ -388,26 +394,27 @@ public interface ConfigurationSection {
* @param path Path of the long to check. * @param path Path of the long to check.
* @return Whether or not the specified path is a long. * @return Whether or not the specified path is a long.
*/ */
public boolean isLong(final String path); boolean isLong(String path);
// Java // Java
/** /**
* Gets the requested List by path. * Gets the requested List by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified, this
* will return the default value. If the List does not exist and no * will return the default value. If the List does not exist and no
* default value was specified, this will return null. * default value was specified, this will return null.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List. * @return Requested List.
*/ */
public List<?> getList(final String path); List<?> getList(String path);
/** /**
* Gets the requested List by path, returning a default value if not * Gets the requested List by path, returning a default value if not
* found. * found.
* <p> *
* If the List does not exist then the specified default value will * <p>If the List does not exist then the specified default value will
* returned regardless of if a default has been identified in the root * returned regardless of if a default has been identified in the root
* {@link Configuration}. * {@link Configuration}.
* *
@ -416,12 +423,12 @@ public interface ConfigurationSection {
* not a List. * not a List.
* @return Requested List. * @return Requested List.
*/ */
public List<?> getList(final String path, final List<?> def); List<?> getList(String path, List<?> def);
/** /**
* Checks if the specified path is a List. * Checks if the specified path is a List.
* <p> *
* If the path exists but is not a List, this will return false. If the * <p>If the path exists but is not a List, this will return false. If the
* path does not exist, this will return false. If the path does not exist * path does not exist, this will return false. If the path does not exist
* but a default value has been specified, this will check if that default * but a default value has been specified, this will check if that default
* value is a List and return appropriately. * value is a List and return appropriately.
@ -429,175 +436,174 @@ public interface ConfigurationSection {
* @param path Path of the List to check. * @param path Path of the List to check.
* @return Whether or not the specified path is a List. * @return Whether or not the specified path is a List.
*/ */
public boolean isList(final String path); boolean isList(String path);
/** /**
* Gets the requested List of String by path. * Gets the requested List of String by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a String if possible, * <p>This method will attempt to cast any values into a String if possible,
* but may miss any values out if they are not compatible. * but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of String. * @return Requested List of String.
*/ */
public List<String> getStringList(final String path); List<String> getStringList(String path);
/** /**
* Gets the requested List of Integer by path. * Gets the requested List of Integer by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a Integer if possible, * <p>This method will attempt to cast any values into a Integer if
* but may miss any values out if they are not compatible. * possible, but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Integer. * @return Requested List of Integer.
*/ */
public List<Integer> getIntegerList(final String path); List<Integer> getIntegerList(String path);
/** /**
* Gets the requested List of Boolean by path. * Gets the requested List of Boolean by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a Boolean if possible, * <p>This method will attempt to cast any values into a Boolean if
* but may miss any values out if they are not compatible. * possible, but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Boolean. * @return Requested List of Boolean.
*/ */
public List<Boolean> getBooleanList(final String path); List<Boolean> getBooleanList(String path);
/** /**
* Gets the requested List of Double by path. * Gets the requested List of Double by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a Double if possible, * <p>This method will attempt to cast any values into a Double if possible,
* but may miss any values out if they are not compatible. * but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Double. * @return Requested List of Double.
*/ */
public List<Double> getDoubleList(final String path); List<Double> getDoubleList(String path);
/** /**
* Gets the requested List of Float by path. * Gets the requested List of Float by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a Float if possible, * <p>This method will attempt to cast any values into a Float if possible,
* but may miss any values out if they are not compatible. * but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Float. * @return Requested List of Float.
*/ */
public List<Float> getFloatList(final String path); List<Float> getFloatList(String path);
/** /**
* Gets the requested List of Long by path. * Gets the requested List of Long by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a Long if possible, * <p>This method will attempt to cast any values into a Long if possible,
* but may miss any values out if they are not compatible. * but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Long. * @return Requested List of Long.
*/ */
public List<Long> getLongList(final String path); List<Long> getLongList(String path);
/** /**
* Gets the requested List of Byte by path. * Gets the requested List of Byte by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a Byte if possible, * <p>This method will attempt to cast any values into a Byte if possible,
* but may miss any values out if they are not compatible. * but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Byte. * @return Requested List of Byte.
*/ */
public List<Byte> getByteList(final String path); List<Byte> getByteList(String path);
/** /**
* Gets the requested List of Character by path. * Gets the requested List of Character by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a Character if * <p>This method will attempt to cast any values into a Character if
* possible, but may miss any values out if they are not compatible. * possible, but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Character. * @return Requested List of Character.
*/ */
public List<Character> getCharacterList(final String path); List<Character> getCharacterList(String path);
/** /**
* Gets the requested List of Short by path. * Gets the requested List of Short by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> *
* This method will attempt to cast any values into a Short if possible, * <p>This method will attempt to cast any values into a Short if
* but may miss any values out if they are not compatible. * possible, but may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Short. * @return Requested List of Short.
*/ */
public List<Short> getShortList(final String path); List<Short> getShortList(String path);
/** /**
* Gets the requested List of Maps by path. * Gets the requested List of Maps by path.
* <p> *
* If the List does not exist but a default value has been specified, this * <p>If the List does not exist but a default value has been specified,
* will return the default value. If the List does not exist and no * this will return the default value. If the List does not exist and no
* default value was specified, this will return an empty List. * default value was specified, this will return an empty List.
* <p> * <p>This method will attempt to cast any values into a Map if possible,
* This method will attempt to cast any values into a Map if possible, but * but may miss any values out if they are not compatible.
* may miss any values out if they are not compatible.
* *
* @param path Path of the List to get. * @param path Path of the List to get.
* @return Requested List of Maps. * @return Requested List of Maps.
*/ */
public List<Map<?, ?>> getMapList(final String path); List<Map<?, ?>> getMapList(String path);
/** /**
* Gets the requested ConfigurationSection by path. * Gets the requested ConfigurationSection by path.
* <p> *
* If the ConfigurationSection does not exist but a default value has been * <p>If the ConfigurationSection does not exist but a default value has
* specified, this will return the default value. If the * been specified, this will return the default value. If the
* ConfigurationSection does not exist and no default value was specified, * ConfigurationSection does not exist and no default value was specified,
* this will return null. * this will return {@code null}.
* *
* @param path Path of the ConfigurationSection to get. * @param path Path of the ConfigurationSection to get.
* @return Requested ConfigurationSection. * @return Requested ConfigurationSection.
*/ */
public ConfigurationSection getConfigurationSection(final String path); ConfigurationSection getConfigurationSection(String path);
/** /**
* Checks if the specified path is a ConfigurationSection. * Checks if the specified path is a ConfigurationSection.
* <p> *
* If the path exists but is not a ConfigurationSection, this will return * <p>If the path exists but is not a ConfigurationSection, this will return
* false. If the path does not exist, this will return false. If the path * false. If the path does not exist, this will return false. If the path
* does not exist but a default value has been specified, this will check * does not exist but a default value has been specified, this will check
* if that default value is a ConfigurationSection and return * if that default value is a ConfigurationSection and return
@ -606,37 +612,37 @@ public interface ConfigurationSection {
* @param path Path of the ConfigurationSection to check. * @param path Path of the ConfigurationSection to check.
* @return Whether or not the specified path is a ConfigurationSection. * @return Whether or not the specified path is a ConfigurationSection.
*/ */
public boolean isConfigurationSection(final String path); boolean isConfigurationSection(String path);
/** /**
* Gets the equivalent {@link ConfigurationSection} from the default * Gets the equivalent {@link ConfigurationSection} from the default
* {@link Configuration} defined in {@link #getRoot()}. * {@link Configuration} defined in {@link #getRoot()}.
* <p> *
* If the root contains no defaults, or the defaults doesn't contain a * <p>If the root contains no defaults, or the defaults doesn't contain a
* value for this path, or the value at this path is not a {@link * value for this path, or the value at this path is not a {@link
* ConfigurationSection} then this will return null. * ConfigurationSection} then this will return {@code null}.
* *
* @return Equivalent section in root configuration * @return Equivalent section in root configuration
*/ */
public ConfigurationSection getDefaultSection(); ConfigurationSection getDefaultSection();
/** /**
* Sets the default value in the root at the given path as provided. * Sets the default value in the root at the given path as provided.
* <p> *
* If no source {@link Configuration} was provided as a default * <p>If no source {@link Configuration} was provided as a default
* collection, then a new {@link MemoryConfiguration} will be created to * collection, then a new {@link MemoryConfiguration} will be created to
* hold the new default value. * hold the new default value.
* <p>
* If value is null, the value will be removed from the default
* Configuration source.
* <p>
* If the value as returned by {@link #getDefaultSection()} is null, then
* this will create a new section at the path, replacing anything that may
* have existed there previously.
* *
* @param path Path of the value to set. * <p>If value is {@code null}, the value will be removed from the
* @param value Value to set the default to. * default Configuration source.
* @throws IllegalArgumentException Thrown if path is null. *
* <p>If the value as returned by {@link #getDefaultSection()} is
* {@code null}, then this will create a new section at the path,
* replacing anything that may have existed there previously.
*
* @param path Path of the value to set
* @param value Value to set the default to
* @throws IllegalArgumentException Thrown if path is {@code null}
*/ */
public void addDefault(final String path, final Object value); void addDefault(String path, Object value);
} }

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