200 Commits

Author SHA1 Message Date
9003831622 First tries to get postgres up and running 2024-04-07 12:36:46 +02:00
43c9fd01a8 Compile against WorldEdit 7.3.0; fix compile 2024-03-10 06:16:25 +01:00
54f9855a1f Merge pull request #892 from IAISI/master
Fix NPE, update dependencies
2024-02-12 06:32:15 +01:00
626ba83b18 Update dependencies 2024-02-07 11:44:31 +01:00
7adf7a1cb4 Fix NPE:
[LogBlock] Could not parse BlockState for PLAYER_HEAD
java.lang.NullPointerException: Cannot invoke "java.util.UUID.toString()" because the return value of "org.bukkit.profile.PlayerProfile.getUniqueId()" is null
	at de.diddiz.LogBlock.blockstate.BlockStateCodecSkull.getChangesAsComponent(BlockStateCodecSkull.java:77) ~[LogBlock.jar:?]
	at de.diddiz.LogBlock.blockstate.BlockStateCodecs.getChangesAsComponent(BlockStateCodecs.java:57) ~[LogBlock.jar:?]
	at de.diddiz.LogBlock.BlockChange.getTypeDetails(BlockChange.java:95) ~[LogBlock.jar:?]
	at de.diddiz.LogBlock.BlockChange.getTypeDetails(BlockChange.java:87) ~[LogBlock.jar:?]
	at de.diddiz.LogBlock.BlockChange.getLogMessage(BlockChange.java:135) ~[LogBlock.jar:?]
	at de.diddiz.LogBlock.CommandsHandler.showPage(CommandsHandler.java:446) ~[LogBlock.jar:?]
	at de.diddiz.LogBlock.CommandsHandler.showPage(CommandsHandler.java:428) ~[LogBlock.jar:?]
	at de.diddiz.LogBlock.CommandsHandler$CommandLookup.run(CommandsHandler.java:578) ~[LogBlock.jar:?]
	at org.bukkit.craftbukkit.v1_20_R3.scheduler.CraftTask.run(CraftTask.java:101) ~[paper-1.20.4.jar:git-Paper-"9e171ef"]
	at org.bukkit.craftbukkit.v1_20_R3.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:57) ~[paper-1.20.4.jar:git-Paper-"9e171ef"]
	at com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:22) ~[paper-1.20.4.jar:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
	at java.lang.Thread.run(Thread.java:840) ~[?:?]
2024-02-07 11:38:13 +01:00
da2264481c Update for 1.20.4 (requires 1.20.4 to run) 2023-12-13 09:33:08 +01:00
e3dda845e2 improve sign change log display 2023-12-09 02:39:59 +01:00
224bc1bae7 only log sign changes whan anything was changed 2023-12-09 02:39:46 +01:00
9c9f923536 Log brushing suspicious sand/gravel 2023-11-13 07:19:54 +01:00
e30e331cce allow mobspawners without spawned type 2023-10-20 06:48:05 +02:00
2671080665 formating... 2023-10-18 04:05:45 +02:00
499573fa66 Fix duplicate set entry & add missing piglin head (#888) 2023-10-17 23:52:13 +02:00
f972bae6ba typo 2023-10-17 08:40:56 +02:00
d7e458ad68 Use Tags for Materials in BukkitUtils (#883) 2023-10-17 08:38:46 +02:00
f2e76a50cb MC Version 1.20.1, use waxed sign api (#884)
* bump api version to 1.20.1
* Sign.isWaxed is now API
2023-10-17 08:33:06 +02:00
fc92ad2307 remove eol setting from .editorconfig 2023-10-09 09:00:31 +02:00
95a8d6043d add .gitattributes 2023-10-09 08:54:12 +02:00
0c21d821d9 Fix line endings 2023-10-09 08:52:12 +02:00
19cc874db8 Add trim_trailing_whitespace to .editorconfig 2023-10-03 03:11:47 +02:00
499cdbca27 Add .editorconfig 2023-10-03 03:11:47 +02:00
f5ddf9f9ec Fix #875
Update HikariCP
slf4j is not needed, removed it
2023-10-02 02:31:45 +02:00
a3069292d0 Bump api-version to 1.20 2023-10-01 05:51:37 +02:00
249ab18091 use mkdirs() instead of mkdir() and fix formatting 2023-09-29 03:24:18 +02:00
337a0502bf Fix #873
Use Bukkit API for plugin Directory
2023-09-29 03:20:59 +02:00
a6b37c03d0 Merge pull request #870 from Joo200/feature/mariadb-connector
MariaDB 11 compatibility fix: configurable protocol
2023-09-22 07:32:41 +02:00
8786dc253e add protocol config option to allow mariadb protocol 2023-08-15 16:29:54 +02:00
1c0c6c2d8b cauldron no longer has levels 2023-07-21 02:57:05 +02:00
547aa81063 improve Reflections.isSignWaxed 2023-06-12 06:26:45 +02:00
f743347e66 sign dyes can only be applied when there is some text on the sign 2023-06-12 05:55:12 +02:00
a6e0e72fb6 cleanup sign logging 2023-06-12 05:54:46 +02:00
5fdecb77cd improve block state display 2023-06-12 05:29:06 +02:00
05269c6978 version is now 1.20 2023-06-12 03:43:20 +02:00
419f3530ad properly log sign edits 2023-06-12 03:41:12 +02:00
31bef400a6 add 1.20 materials 2023-06-11 05:24:15 +02:00
1fce7c7a66 avoid invalid fluid levels 2023-06-02 05:25:12 +02:00
a609c021e6 1.19.4 2023-03-17 05:33:58 +01:00
e4fb0f38d1 No more enums 2023-03-17 05:30:40 +01:00
154de294a4 use a better method 2023-02-07 04:41:58 +01:00
d347a25a02 Updates for 1.19.3: Log hanging signs and add some missing materials 2023-02-07 04:30:24 +01:00
b3e829d1be add bamboo blocks (requires 1.19.3) 2023-01-18 06:09:55 +01:00
c3ae8358dd better log rollback exceptions 2023-01-03 04:59:42 +01:00
5d91d5abb7 "/lb sum entities" should list entities, not blocks 2022-11-03 06:04:11 +01:00
7c690c707a port to exact height when player is in specator mode 2022-11-03 06:01:57 +01:00
0bd211083b do not log golems by default 2022-11-03 05:56:41 +01:00
a395f206bd Log respawn anchor explosions 2022-11-03 05:56:30 +01:00
4faced94d4 separate logging option for wateranimals 2022-11-03 05:41:41 +01:00
0f459440be New entity logging option logAllNamedEntityKills 2022-11-03 05:36:55 +01:00
43864ad002 Remove unused config option 2022-09-30 05:26:14 +02:00
c34ad1ca0f Allow minecraft names instead of bukkit names for entities 2022-09-09 07:47:12 +02:00
0e601aa174 add config option if natural entity spawns should be logged 2022-08-03 05:44:57 +02:00
9bfe5d09cd use long when accessing id columns 2022-08-03 05:05:44 +02:00
c6e8105c0e add newline before log output to improve readability 2022-08-03 04:36:09 +02:00
b658d3799b add missing 1.19 materials 2022-07-14 05:31:24 +02:00
86100c1830 version 1.19.0.0-SNAPSHOT 2022-07-03 07:36:40 +02:00
7791c4e960 fix player names with underscore 2022-06-16 21:32:51 +02:00
62a5be6c6b log sculk 2022-06-11 20:39:23 +02:00
0ed501493e Update for Minecraft 19
* Update build plugins
* Update dependencies
* Require Java 17
2022-06-11 20:20:09 +02:00
81457ced65 improve player name parsing 2022-06-11 20:14:48 +02:00
c3394fa8c5 Save full skull profile instead of just the uuid if available 2022-02-16 08:38:50 +01:00
e61f9b058d Fix world height during safe teleport 2022-02-01 20:42:48 +01:00
1b2948c912 use https for xml schema location 2022-01-08 21:49:07 +01:00
8def317c62 Revert "exclude worldedit dependencies (#850)"
This reverts commit 676f862d2d.
2022-01-07 21:34:19 +01:00
676f862d2d exclude worldedit dependencies (#850)
Co-authored-by: qwertyuioplkjhgfd <qwertyuioplkjhgfd@users.noreply.github.com>
2022-01-07 01:46:51 +01:00
6d0ac7169c update enginehub repository location (#849) 2022-01-05 01:37:45 +01:00
5e9be562cd fix candle logging 2021-12-19 09:25:20 +01:00
4e4b5de15d fix some y column types on startup if required 2021-12-19 07:27:37 +01:00
eac1008525 ItemStack.getTagClone is private so we have to use setAccessible 2021-12-19 06:41:10 +01:00
e87e9e2939 Fix itemstack reflection 2021-12-06 03:58:39 +01:00
31589ceec7 Build against spigot-api 1.18 2021-12-06 03:58:16 +01:00
749d114acd Fix issues with minecraft 1.18 2021-12-01 07:48:03 +01:00
964e60b2e5 update distribution repository 2021-11-08 05:49:33 +01:00
142bcae2ca Add feature to disable logging in WorldGuard regions
resolves #826
2021-08-27 03:22:29 +02:00
5dfee1f906 Load config in onLoad 2021-08-27 02:43:18 +02:00
e430ee073f Move all classes to the logblock package 2021-08-27 02:25:11 +02:00
c940dfc05a Store the acting entity object in the actor class 2021-08-26 21:16:40 +02:00
610f3edcab Add EntityChangePreLogEvent 2021-08-26 20:54:55 +02:00
597b1831f1 Normalize actor for crop trampling mobs 2021-08-26 20:53:42 +02:00
d084372876 Simplify Actor.actorFromString 2021-08-26 08:07:28 +02:00
4b7b5b984d Remove fireCustomEvents config option / fire event when any listener is registered 2021-08-26 07:58:44 +02:00
522def8b2e Add a warning that the table conversion for 1.17 might take a long time 2021-08-23 19:41:23 +02:00
b3f268cd04 Avoid deprecated methods when creating the item hover and some cleanup 2021-08-21 00:01:15 +02:00
f2f988b15b Added more pleasant HoverEvent (#835)
* Added more pleasant hoverevent

* Remove synchronized

* Changed item amount

* Requested changes
2021-08-20 23:49:58 +02:00
3730aa92c4 Log breaking dripstone
Fixes #831
2021-08-17 05:54:13 +02:00
5aac2d712b Fix logging blocks below 0
Fixes #834
2021-08-17 05:47:37 +02:00
701f434fae cancel auto clearlog when plugin is disabled 2021-07-12 05:08:03 +02:00
07924138ea Add cauldron interact logging 2021-07-12 04:28:16 +02:00
9c2caa6af8 Better display sign changes in log messages 2021-07-12 03:57:36 +02:00
1e1243449f Log make signs glowing/unglowing 2021-07-12 03:32:09 +02:00
7f3837f1fe Fix logging bonemealing moss 2021-07-09 06:27:21 +02:00
9399b7062e Update to 1.17 2021-06-29 05:23:17 +02:00
a58206b21d Add End Crystal logging
Fixes #830
2021-06-23 05:50:32 +02:00
aca0127781 Update spigot dependency to 1.16.5 2021-06-23 05:48:06 +02:00
1a9827cc32 Explosion logging: Move WitherSkull up, because it is a Fireball too 2021-06-11 04:03:37 +02:00
cf8da11cca Fix setting actor when a creeper causes an explosion 2021-04-30 04:05:30 +02:00
8e3f5aca56 Improve entity killer logging
Fixes #622
2021-04-29 20:37:38 +02:00
2d9456409c Remove accidentally committed debug logging 2021-04-29 16:27:14 +02:00
f0e3353fc9 Prettier help formating
Fixes #592
2021-04-28 05:21:13 +02:00
721b51383c Merge branch 'master' into inventory-logging
Fixes #817, #774, #770, #676, #565
2021-04-28 04:51:46 +02:00
cb1231eab5 Snapshots 2021-04-15 03:23:55 +02:00
1df380741b Release 1.16.5.1 2021-04-15 03:19:14 +02:00
2049a7a7a4 Use a different way to check for existing tables 2021-04-14 18:52:06 +02:00
8148386e3e Back to snapshots 2021-04-13 21:01:37 +02:00
87074da8a1 Release Logblock 1.16.5 2021-04-13 20:53:56 +02:00
0fd3266c7b Load the new mysql driver class if available 2021-04-13 18:32:16 +02:00
c20b677507 Improve table creation logic 2021-04-13 18:24:54 +02:00
fe7e244898 Do not scroll in a result set when we don't have to 2021-03-18 21:25:10 +01:00
4f7c02b285 Flush other viewers of the same inventory; add some documentation 2021-02-22 07:42:50 +01:00
8a8471c3e6 Initial work for improved inventory logging 2021-02-22 00:18:02 +01:00
fe98370acd Avoid syncronous query in /lb me
and improve changes count display in sumarized changes

Fixes #819
2021-02-20 06:32:53 +01:00
76df1a4913 Use GSON in UUIDFetcher 2021-02-17 07:31:50 +01:00
841ce89f21 UUIDs are stored differently since 1.16 2021-02-17 07:10:51 +01:00
033a53e338 Improve database upgrade logic 2021-01-30 17:34:24 +01:00
f42649adc3 Do not forget to close connection when upgrading a table fails 2021-01-29 20:10:43 +01:00
81e0135046 Remove tool from offhand if it is not found in the main inventory 2021-01-16 07:37:56 +01:00
e181c85647 Fix table update and to not break on update issues 2021-01-16 07:16:01 +01:00
dde8dc8289 Do not log bees leaving beehives 2021-01-16 06:21:53 +01:00
ac462261dc Add missing entityid index for entities tables 2021-01-16 06:20:36 +01:00
42715de265 getExistingEntityTypeId should return Integer instead of int
Fixes #804
2020-08-31 00:28:12 +02:00
d548206c3a Workaround for SPIGOT-6025 (catch the exception and log it) 2020-08-28 05:34:48 +02:00
24b5455f08 Use Spigots new HoverEvent api 2020-08-23 07:10:11 +02:00
35f921a9a0 Fix loading old walls 2020-08-23 05:40:15 +02:00
0d7a8016a1 Do not add unnecessary materials or entity types to the database 2020-08-09 23:25:30 +02:00
6a398a67ab Protect against sql injections when using the api 2020-07-20 07:13:32 +02:00
6dcca54637 Do not use the numeric material/entity ids for the api 2020-07-20 06:47:43 +02:00
650f7e20f1 Make MaterialConverter and EntityTypeConverter thread safe 2020-07-20 06:17:06 +02:00
5c22beb2e5 Make MaterialConverter type safe 2020-07-20 06:02:23 +02:00
a63c97bd70 Back to snapshots 2020-07-11 05:45:35 +02:00
1562bbacea Release 1.16.1.1 2020-07-11 05:43:54 +02:00
aba6e4d9c8 Add some missing special block handlings for 1.16 2020-07-02 04:33:18 +02:00
1ef7c78c0d Snapshots for 1.16.1.1 2020-06-27 22:45:20 +02:00
788d8fd4d5 Release 1.16.1.0 2020-06-27 22:43:33 +02:00
3bfb19cdfa Correctly log 1.16 blocks 2020-06-27 22:40:08 +02:00
04b5d9e7ed Snapshots for 1.16.1 2020-06-27 22:39:29 +02:00
a96f82efae Back to snapshots 2020-02-13 05:09:27 +01:00
39f58a6bd4 Release 1.15.2 2020-02-13 05:05:21 +01:00
e1064dd0b1 Load mysql driver on startup
Fixes #784
2020-02-13 04:17:01 +01:00
fc1cd5ef2c Fix oldConfig check 2020-02-08 17:33:39 +01:00
1dba9f20f1 create tables and register events if logging commands 2020-01-26 06:27:09 +01:00
8eb93411ec Configurable command logging 2020-01-26 03:21:12 +01:00
068ac89819 Add optional logging of shulker box contents
Fixes #781
2020-01-24 05:51:18 +01:00
6b71a3c30d smart log breaking ice 2020-01-24 05:17:33 +01:00
6dec1b6c37 Improve rollback ability by accepting similar blocks to the expected one
For example grass_block instead of dirt
2020-01-24 05:06:48 +01:00
b9513df20e Log bamboo growth (new world logging option)
Fixes #769
2020-01-24 04:52:13 +01:00
8b34e39797 Log getting stung by bees
Fixes #780
2020-01-24 04:23:59 +01:00
1cda6506c7 Merge pull request #782 from TheMolkaPL/tool-event
Call ToolUseEvent when a tool is about to be used
2020-01-24 03:49:44 +01:00
5b0e2d9adb Call ToolUseEvent when a tool is about to be used 2020-01-21 17:44:56 +01:00
cdf6c1df04 Fix conversion to roman numbers
Fixes #779
2019-12-27 18:04:41 +01:00
cdee5b3609 Back to snapshots 2019-12-20 05:37:55 +01:00
8e948e857f Release 1.15.1 2019-12-20 05:27:55 +01:00
793df218e5 Bump version to 1.15.1, update dependencies 2019-12-20 05:27:24 +01:00
31428d60e4 Add some hover texts and clickable coords 2019-12-20 05:15:45 +01:00
169328e159 Use ChatComponent API for log messages 2019-12-18 01:33:40 +01:00
60a771224b improve logging of entitiy damaged by projectiles or tnt 2019-12-01 05:14:10 +01:00
3135fe8696 Merge branch 'master' into pretty-chat 2019-11-24 06:19:05 +01:00
59d0794c3d Improve scaffolding logging with fallable blocks
- Log fallable blocks above scaffoldings
- Log scaffolding breaking because blocks below are falling down
2019-11-24 06:16:07 +01:00
8214e7d177 Log falling scaffoldings 2019-11-24 05:46:51 +01:00
e77e95cae0 Merge branch 'master' into pretty-chat 2019-11-17 04:00:59 +01:00
241a7adc48 Wildcard block names in querys
For example "*_slab" to match any slab
2019-11-17 04:00:34 +01:00
27cc59f922 Merge branch 'master' into pretty-chat 2019-11-17 03:19:33 +01:00
8192aa4fb8 Allow block tags in querys
"block #signs" and similar: https://minecraft.gamepedia.com/Tag#List_of_tags
2019-11-17 03:17:32 +01:00
078fe7f423 missing diff for log formatting 2019-10-16 02:37:07 +02:00
76a81c124a Merge branch 'master' into pretty-chat 2019-10-16 02:25:43 +02:00
d98d46d0c9 Fix logging when waterlogging waterlogged blocks 2019-10-16 00:52:29 +02:00
1e1dce99c0 Merge remote-tracking branch 'remotes/origin/master' into pretty-chat 2019-09-30 06:15:29 +02:00
921df872d1 Expose useSSL flag to config 2019-09-30 06:11:26 +02:00
cd38ac9866 Remove unused methods 2019-08-27 22:30:37 +02:00
a7967e9b1e Do not require WorldEdit for CuboidRegion 2019-08-27 20:10:12 +02:00
af895aa21d Merge branch 'master' into pretty-chat 2019-08-11 06:09:24 +02:00
2f92fd3426 Fix beacon logging, they are not a container 2019-08-11 04:56:13 +02:00
f298a5f70f Merge branch 'master' into pretty-chat 2019-08-10 04:34:22 +02:00
091bdca142 Merge pull request #763 from paul-maxime/public-chestaccess
Add public to the ChestAccess variables
2019-08-10 04:25:48 +02:00
07bf9421dd Switch to openjdk8 in travis builds 2019-08-10 04:24:03 +02:00
06f24bf632 Add public to the ChestAccess variables 2019-08-10 00:24:27 +02:00
3f7ace7f70 Merge branch 'master' into pretty-chat 2019-07-09 03:46:09 +02:00
6f4ce7e6d0 Fix lectern logging
Fixes #761
2019-07-09 03:42:33 +02:00
d03bbe68ba Add missing newline 2019-06-24 04:14:52 +02:00
e9d78bffb1 Change action type for some entries 2019-06-23 21:59:07 +02:00
d829005c7e Apply new message formatting to entity changes 2019-06-23 21:57:21 +02:00
a6e4d79e0c Merge remote-tracking branch 'remotes/DarkArk/feature/pretty-chat' into pretty-chat 2019-06-23 21:47:14 +02:00
e8aaadf37b Code style 2019-06-23 17:14:17 +02:00
1525d7682f Reformat 2019-06-23 16:45:14 +02:00
76f7f8701d Improve logging of 1.14 blocks 2019-06-23 05:23:31 +02:00
9b5e0c9025 WorldEdit logging should only log modified blocks
Fixes #757
2019-06-23 05:22:18 +02:00
e6b0108bc5 Chunk.load is just as World.loadChunk 2019-06-20 06:08:59 +02:00
3efd92d9df loadChunk will keep chunks loaded forever, so do not use that 2019-06-20 05:37:55 +02:00
05d7652bcc Improve log messages when the block/entity type is unknown 2019-05-31 18:00:55 +02:00
72fc78b3c0 Add missing break 2019-05-28 07:30:56 +02:00
9eef03aa90 Fix lectern logging 2019-05-28 06:07:57 +02:00
da692ed01a Log lectern book change 2019-05-28 05:25:25 +02:00
424ef3b02b Only log sign base color changes when we log SIGNTEXT for this world 2019-05-27 23:53:50 +02:00
4fda020dfc Log sign base color change 2019-05-27 22:46:32 +02:00
8f429afbeb Made LogBlock's messages far more visual appealing 2019-05-20 23:29:29 -04:00
f6522b73f4 create chat table without fulltext index if the database does not support it. 2019-05-16 01:35:46 +02:00
ac233a3920 Spigot 1.14.1 2019-05-14 17:59:30 +02:00
7a946fc23d Merge branch 'master' into 1.14pre 2019-05-14 17:56:39 +02:00
33c18a9e62 Improve compatibility when running 1.13 and 1.14 servers on the same logblock database
Old materials are no longer renamed, instead new materials are added and the old entries are modified
2019-05-05 05:55:47 +02:00
e66b5a8f9d Merge branch 'master' into 1.14pre 2019-05-04 17:50:48 +02:00
503541ad4e Fix version parsing 2019-05-02 21:51:16 +02:00
82d61d5ee7 Spigot 1.14 instead of 1.14-pre5 2019-04-27 04:53:34 +02:00
254c856b2f Update to 1.14pre5 2019-04-24 17:49:52 +02:00
99 changed files with 11076 additions and 8374 deletions

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
root = true
[*]
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[*.java]
indent_style = space
indent_size = 4
[*.yml]
indent_style = space
indent_size = 2

11
.gitattributes vendored Normal file
View File

@ -0,0 +1,11 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.java text
*.txt text
*.yml text
*.xml text
*.md text
LICENSE text

View File

@ -1,5 +1,5 @@
language: java
jdk:
- oraclejdk8
- openjdk8
notifications:
email: false

59
pom.xml
View File

@ -1,10 +1,10 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.diddiz</groupId>
<artifactId>logblock</artifactId>
<version>1.13.2-SNAPSHOT</version>
<version>1.20.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>LogBlock</name>
@ -29,12 +29,14 @@
<distributionManagement>
<repository>
<id>md_5-releases</id>
<url>https://repo.md-5.net/content/repositories/releases/</url>
<id>nexus</id>
<name>Releases</name>
<url>https://www.iani.de/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>md_5-snapshots</id>
<url>https://repo.md-5.net/content/repositories/snapshots/</url>
<id>nexus</id>
<name>Snapshot</name>
<url>https://www.iani.de/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
@ -42,41 +44,31 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.13.2-R0.1-SNAPSHOT</version>
<version>1.20.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>7.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldguard</groupId>
<artifactId>worldguard-bukkit</artifactId>
<version>7.1.0-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
</exclusion>
<exclusion>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.25</version>
<version>5.1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
@ -87,7 +79,7 @@
</repository>
<repository>
<id>sk89q-repo</id>
<url>https://maven.sk89q.com/repo/</url>
<url>https://maven.enginehub.org/repo/</url>
</repository>
<repository>
<id>brokkonaut-repo</id>
@ -133,16 +125,15 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<version>3.12.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<release>17</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<version>3.5.0</version>
<executions>
<execution>
<id>regex-property</id>
@ -162,7 +153,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<version>3.5.1</version>
<configuration>
</configuration>
<executions>
@ -177,10 +168,6 @@
<pattern>com.zaxxer.hikari</pattern>
<shadedPattern>de.diddiz.lib.com.zaxxer.hikari</shadedPattern>
</relocation>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>de.diddiz.lib.org.slf4j</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>

View File

@ -1,157 +1,182 @@
package de.diddiz.LogBlock;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.projectiles.BlockProjectileSource;
import org.bukkit.projectiles.ProjectileSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import static de.diddiz.util.BukkitUtils.entityName;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
public class Actor {
@Override
public int hashCode() {
return this.UUID != null ? this.UUID.hashCode() : 0;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Actor other = (Actor) obj;
return (this.UUID == null) ? (other.UUID == null) : this.UUID.equals(other.UUID);
}
final String name;
final String UUID;
final Location blockLocation;
public Actor(String name, String UUID) {
this.name = name;
this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID);
this.blockLocation = null;
}
public Actor(String name, String UUID, Block block) {
this.name = name;
this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID);
this.blockLocation = block == null ? null : block.getLocation();
}
public Actor(String name, java.util.UUID UUID) {
this.name = name;
this.UUID = UUID.toString();
this.blockLocation = null;
}
public Actor(String name, java.util.UUID UUID, Block block) {
this.name = name;
this.UUID = UUID.toString();
this.blockLocation = block == null ? null : block.getLocation();
}
public Actor(String name) {
this(name, generateUUID(name));
}
public Actor(String name, Block block) {
this(name, generateUUID(name), block);
}
public Actor(ResultSet rs) throws SQLException {
this(rs.getString("playername"), rs.getString("UUID"));
}
public String getName() {
return name;
}
public String getUUID() {
return UUID;
}
public Location getBlockLocation() {
return blockLocation;
}
public static Actor actorFromEntity(Entity entity) {
if (entity instanceof Player) {
return new Actor(entityName(entity), entity.getUniqueId());
}
if (entity instanceof Projectile) {
ProjectileSource shooter = ((Projectile) entity).getShooter();
if (shooter != null) {
return actorFromProjectileSource(shooter);
}
}
return new Actor(entityName(entity));
}
public static Actor actorFromEntity(EntityType entity) {
return new Actor(entity.name());
}
public static Actor actorFromProjectileSource(ProjectileSource psource) {
if (psource instanceof Entity) {
return actorFromEntity((Entity) psource);
}
if (psource instanceof BlockProjectileSource) {
return new Actor(((BlockProjectileSource) psource).getBlock().getType().toString());
} else {
return new Actor(psource.toString());
}
}
/**
* Generate an Actor object from a String name, trying to guess if it's an online player
* and if so, setting the UUID accordingly. This only checks against currently online
* players and is a "best effort" attempt for use with the pre-UUID API
* <p>
* If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) }
* or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods
* <p>
* If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)}
*
* @deprecated Only use this if you have a String of unknown origin
*
* @param actorName
* String of unknown origin
* @return
*/
public static Actor actorFromString(String actorName) {
Collection<? extends Player> players = Bukkit.getServer().getOnlinePlayers();
for (Player p : players) {
if (p.getName().equalsIgnoreCase(actorName)) {
return actorFromEntity(p);
}
}
// No player found online with that name, assuming non-player entity/effect
return new Actor(actorName);
}
public static boolean isValidUUID(String uuid) {
try {
java.util.UUID.fromString(uuid);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
public static String generateUUID(String name) {
return "log_" + name;
}
}
package de.diddiz.LogBlock;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.projectiles.BlockProjectileSource;
import org.bukkit.projectiles.ProjectileSource;
import static de.diddiz.LogBlock.util.BukkitUtils.entityName;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
public class Actor {
@Override
public int hashCode() {
return this.UUID != null ? this.UUID.hashCode() : 0;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Actor other = (Actor) obj;
return (this.UUID == null) ? (other.UUID == null) : this.UUID.equals(other.UUID);
}
final String name;
final String UUID;
final Location blockLocation;
final Entity entity;
public Actor(String name, String UUID) {
this.name = name;
this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID);
this.blockLocation = null;
this.entity = null;
}
public Actor(String name, String UUID, Block block) {
this.name = name;
this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID);
this.blockLocation = block == null ? null : block.getLocation();
this.entity = null;
}
public Actor(String name, java.util.UUID UUID) {
this.name = name;
this.UUID = UUID.toString();
this.blockLocation = null;
this.entity = null;
}
public Actor(String name, java.util.UUID UUID, Block block) {
this.name = name;
this.UUID = UUID.toString();
this.blockLocation = block == null ? null : block.getLocation();
this.entity = null;
}
public Actor(String name, java.util.UUID UUID, Entity entity) {
this.name = name;
this.UUID = UUID.toString();
this.blockLocation = null;
this.entity = entity;
}
public Actor(String name) {
this(name, generateUUID(name));
}
public Actor(String name, Block block) {
this(name, generateUUID(name), block);
}
public Actor(String name, Entity entity) {
this.name = name;
this.UUID = generateUUID(name);
this.blockLocation = null;
this.entity = entity;
}
public Actor(ResultSet rs) throws SQLException {
this(rs.getString("playername"), rs.getString("UUID"));
}
public String getName() {
return name;
}
public String getUUID() {
return UUID;
}
public Location getBlockLocation() {
return blockLocation;
}
/**
* The acting entity object (if known)
*/
public Entity getEntity() {
return entity;
}
public static Actor actorFromEntity(Entity entity) {
if (entity instanceof Player) {
return new Actor(entityName(entity), entity.getUniqueId(), entity);
}
if (entity instanceof Projectile) {
ProjectileSource shooter = ((Projectile) entity).getShooter();
if (shooter != null) {
return actorFromProjectileSource(shooter);
}
}
return new Actor(entityName(entity), entity);
}
@Deprecated
public static Actor actorFromEntity(EntityType entity) {
return new Actor(entity.name());
}
public static Actor actorFromProjectileSource(ProjectileSource psource) {
if (psource instanceof Entity) {
return actorFromEntity((Entity) psource);
}
if (psource instanceof BlockProjectileSource) {
return new Actor(((BlockProjectileSource) psource).getBlock().getType().toString());
} else {
return new Actor(psource.toString());
}
}
/**
* Generate an Actor object from a String name, trying to guess if it's an online player
* and if so, setting the UUID accordingly. This only checks against currently online
* players and is a "best effort" attempt for use with the pre-UUID API
* <p>
* If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) }
* or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods
* <p>
* If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)}
*
* @deprecated Only use this if you have a String of unknown origin
*
* @param actorName
* String of unknown origin
* @return
*/
@Deprecated
public static Actor actorFromString(String actorName) {
Player p = Bukkit.getServer().getPlayerExact(actorName);
if (p != null) {
return actorFromEntity(p);
}
// No player found online with that name, assuming non-player entity/effect
return new Actor(actorName);
}
public static boolean isValidUUID(String uuid) {
try {
java.util.UUID.fromString(uuid);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
public static String generateUUID(String name) {
return "log_" + name;
}
}

View File

@ -1,29 +1,32 @@
package de.diddiz.LogBlock;
import java.util.Arrays;
import java.util.logging.Level;
import static de.diddiz.LogBlock.config.Config.autoClearLog;
import static org.bukkit.Bukkit.*;
public class AutoClearLog implements Runnable {
private final LogBlock logblock;
AutoClearLog(LogBlock logblock) {
this.logblock = logblock;
}
@Override
public void run() {
final CommandsHandler handler = logblock.getCommandsHandler();
for (final String paramStr : autoClearLog) {
try {
final QueryParams params = new QueryParams(logblock, getConsoleSender(), Arrays.asList(paramStr.split(" ")));
params.noForcedLimit = true;
handler.new CommandClearLog(getServer().getConsoleSender(), params, false);
} catch (final Exception ex) {
getLogger().log(Level.SEVERE, "Failed to schedule auto ClearLog: ", ex);
}
}
}
}
package de.diddiz.LogBlock;
import java.util.Arrays;
import java.util.logging.Level;
import static de.diddiz.LogBlock.config.Config.autoClearLog;
import static org.bukkit.Bukkit.*;
public class AutoClearLog implements Runnable {
private final LogBlock logblock;
AutoClearLog(LogBlock logblock) {
this.logblock = logblock;
}
@Override
public void run() {
final CommandsHandler handler = logblock.getCommandsHandler();
for (final String paramStr : autoClearLog) {
if (!logblock.isCompletelyEnabled()) {
return; // do not try when plugin is disabled
}
try {
final QueryParams params = new QueryParams(logblock, getConsoleSender(), Arrays.asList(paramStr.split(" ")));
params.noForcedLimit = true;
handler.new CommandClearLog(getServer().getConsoleSender(), params, false);
} catch (final Exception ex) {
getLogger().log(Level.SEVERE, "Failed to schedule auto ClearLog: ", ex);
}
}
}
}

View File

@ -1,181 +1,272 @@
package de.diddiz.LogBlock;
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.util.BukkitUtils;
import de.diddiz.util.Utils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Note;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Openable;
import org.bukkit.block.data.Powerable;
import org.bukkit.block.data.type.Comparator;
import org.bukkit.block.data.type.DaylightDetector;
import org.bukkit.block.data.type.NoteBlock;
import org.bukkit.block.data.type.Repeater;
import org.bukkit.block.data.type.Switch;
import org.bukkit.inventory.ItemStack;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
public class BlockChange implements LookupCacheElement {
public final long id, date;
public final Location loc;
public final Actor actor;
public final String playerName;
public final int replacedMaterial, replacedData, typeMaterial, typeData;
public final byte[] replacedState, typeState;
public final ChestAccess ca;
public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) {
id = 0;
this.date = date;
this.loc = loc;
this.actor = actor;
this.replacedMaterial = replaced;
this.replacedData = replacedData;
this.replacedState = replacedState;
this.typeMaterial = type;
this.typeData = typeData;
this.typeState = typeState;
this.ca = ca;
this.playerName = actor == null ? null : actor.getName();
}
public BlockChange(ResultSet rs, QueryParams p) throws SQLException {
id = p.needId ? rs.getInt("id") : 0;
date = p.needDate ? rs.getTimestamp("date").getTime() : 0;
loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null;
actor = p.needPlayer ? new Actor(rs) : null;
playerName = p.needPlayer ? rs.getString("playername") : null;
replacedMaterial = p.needType ? rs.getInt("replaced") : 0;
replacedData = p.needType ? rs.getInt("replacedData") : -1;
typeMaterial = p.needType ? rs.getInt("type") : 0;
typeData = p.needType ? rs.getInt("typeData") : -1;
replacedState = p.needType ? rs.getBytes("replacedState") : null;
typeState = p.needType ? rs.getBytes("typeState") : null;
ChestAccess catemp = null;
if (p.needChestAccess) {
ItemStack stack = Utils.loadItemStack(rs.getBytes("item"));
if (stack != null) {
catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype"));
}
}
ca = catemp;
}
@Override
public String toString() {
BlockData type = getBlockSet();
BlockData replaced = getBlockReplaced();
if (type == null || replaced == null) {
return "Unknown block modification";
}
String typeDetails = null;
if (BlockStateCodecs.hasCodec(type.getMaterial())) {
try {
typeDetails = BlockStateCodecs.toString(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState));
} catch (Exception e) {
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e);
}
}
if (typeDetails == null) {
typeDetails = "";
} else {
typeDetails = " " + typeDetails;
}
String replacedDetails = null;
if (BlockStateCodecs.hasCodec(replaced.getMaterial())) {
try {
replacedDetails = BlockStateCodecs.toString(replaced.getMaterial(), Utils.deserializeYamlConfiguration(replacedState));
} catch (Exception e) {
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + replaced.getMaterial(), e);
}
}
if (replacedDetails == null) {
replacedDetails = "";
} else {
replacedDetails = " " + replacedDetails;
}
final StringBuilder msg = new StringBuilder();
if (date > 0) {
msg.append(Config.formatter.format(date)).append(" ");
}
if (actor != null) {
msg.append(actor.getName()).append(" ");
}
if (type.getMaterial().equals(replaced.getMaterial())) {
if (BukkitUtils.isEmpty(type.getMaterial())) {
msg.append("did an unspecified action");
} else if (ca != null) {
if (ca.itemStack == null) {
msg.append("looked inside ").append(type.getMaterial().name());
} else if (ca.remove) {
msg.append("took ").append(BukkitUtils.toString(ca.itemStack)).append(" from ").append(type.getMaterial().name());
} else {
msg.append("put ").append(BukkitUtils.toString(ca.itemStack)).append(" into ").append(type.getMaterial().name());
}
} else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) {
msg.append("opened ").append(type.getMaterial().name());
} else if (type instanceof Openable) {
// Door, Trapdoor, Fence gate
msg.append(((Openable)type).isOpen() ? "opened" : "closed").append(" ").append(type.getMaterial().name());
} else if (type.getMaterial() == Material.LEVER) {
msg.append("switched ").append(type.getMaterial().name()).append(" ").append(((Switch) type).isPowered() ? "on" : "off");
} else if (type instanceof Switch) {
msg.append("pressed ").append(type.getMaterial().name());
} else if (type.getMaterial() == Material.CAKE) {
msg.append("ate a piece of ").append(type.getMaterial().name());
} else if (type.getMaterial() == Material.NOTE_BLOCK) {
Note note = ((NoteBlock) type).getNote();
msg.append("set ").append(type.getMaterial().name()).append(" to ").append(note.getTone().name()).append(note.isSharped() ? "#" : "");
} else if (type.getMaterial() == Material.REPEATER) {
msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((Repeater) type).getDelay()).append(" ticks delay");
} else if (type.getMaterial() == Material.COMPARATOR) {
msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((Comparator) type).getMode());
} else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) {
msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((DaylightDetector) type).isInverted() ? "inverted" : "normal");
} else if (type instanceof Powerable) {
msg.append("stepped on ").append(type.getMaterial().name());
} else if (type.getMaterial() == Material.TRIPWIRE) {
msg.append("ran into ").append(type.getMaterial().name());
} else if (type.getMaterial() == Material.SIGN || type.getMaterial() == Material.WALL_SIGN) {
msg.append("edited a ").append(type.getMaterial().name()).append(" to ").append(typeDetails);
} else {
msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails);
}
} else if (BukkitUtils.isEmpty(type.getMaterial())) {
msg.append("destroyed ").append(replaced.getMaterial().name()).append(replacedDetails);
} else if (BukkitUtils.isEmpty(replaced.getMaterial())) {
msg.append("created ").append(type.getMaterial().name()).append(typeDetails);
} else {
msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails);
}
if (loc != null) {
msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ());
}
return msg.toString();
}
public BlockData getBlockReplaced() {
return MaterialConverter.getBlockData(replacedMaterial, replacedData);
}
public BlockData getBlockSet() {
return MaterialConverter.getBlockData(typeMaterial, typeData);
}
@Override
public Location getLocation() {
return loc;
}
@Override
public String getMessage() {
return toString();
}
}
package de.diddiz.LogBlock;
import static de.diddiz.LogBlock.util.ActionColor.CREATE;
import static de.diddiz.LogBlock.util.ActionColor.DESTROY;
import static de.diddiz.LogBlock.util.ActionColor.INTERACT;
import static de.diddiz.LogBlock.util.MessagingUtil.createTextComponentWithColor;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyState;
import static de.diddiz.LogBlock.util.TypeColor.DEFAULT;
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
import de.diddiz.LogBlock.util.BukkitUtils;
import de.diddiz.LogBlock.util.Utils;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Note;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Lightable;
import org.bukkit.block.data.Openable;
import org.bukkit.block.data.Powerable;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Candle;
import org.bukkit.block.data.type.Comparator;
import org.bukkit.block.data.type.DaylightDetector;
import org.bukkit.block.data.type.Lectern;
import org.bukkit.block.data.type.NoteBlock;
import org.bukkit.block.data.type.Repeater;
import org.bukkit.block.data.type.Sign;
import org.bukkit.block.data.type.Switch;
import org.bukkit.block.data.type.WallSign;
import org.bukkit.inventory.ItemStack;
public class BlockChange implements LookupCacheElement {
public final long id, date;
public final Location loc;
public final Actor actor;
public final String playerName;
public final int replacedMaterial, replacedData, typeMaterial, typeData;
public final byte[] replacedState, typeState;
public final ChestAccess ca;
public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) {
id = 0;
this.date = date;
this.loc = loc;
this.actor = actor;
this.replacedMaterial = replaced;
this.replacedData = replacedData;
this.replacedState = replacedState;
this.typeMaterial = type;
this.typeData = typeData;
this.typeState = typeState;
this.ca = ca;
this.playerName = actor == null ? null : actor.getName();
}
public BlockChange(ResultSet rs, QueryParams p) throws SQLException {
id = p.needId ? rs.getLong("id") : 0;
date = p.needDate ? rs.getTimestamp("date").getTime() : 0;
loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null;
actor = p.needPlayer ? new Actor(rs) : null;
playerName = p.needPlayer ? rs.getString("playername") : null;
replacedMaterial = p.needType ? rs.getInt("replaced") : 0;
replacedData = p.needType ? rs.getInt("replacedData") : -1;
typeMaterial = p.needType ? rs.getInt("type") : 0;
typeData = p.needType ? rs.getInt("typeData") : -1;
replacedState = p.needType ? rs.getBytes("replacedState") : null;
typeState = p.needType ? rs.getBytes("typeState") : null;
ChestAccess catemp = null;
if (p.needChestAccess) {
ItemStack stack = Utils.loadItemStack(rs.getBytes("item"));
if (stack != null) {
catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype"));
}
}
ca = catemp;
}
private BaseComponent getTypeDetails(BlockData type, byte[] typeState) {
return getTypeDetails(type, typeState, null, null);
}
private BaseComponent getTypeDetails(BlockData type, byte[] typeState, BlockData oldType, byte[] oldTypeState) {
BaseComponent typeDetails = null;
if (BlockStateCodecs.hasCodec(type.getMaterial())) {
try {
typeDetails = BlockStateCodecs.getChangesAsComponent(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState), type.equals(oldType) ? Utils.deserializeYamlConfiguration(oldTypeState) : null);
} catch (Exception e) {
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e);
}
}
if (typeDetails == null) {
return new TextComponent("");
} else {
TextComponent component = new TextComponent(" ");
component.addExtra(typeDetails);
return component;
}
}
@Override
public String toString() {
return BaseComponent.toPlainText(getLogMessage(-1));
}
@Override
public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent();
if (date > 0) {
msg.addExtra(prettyDate(date));
msg.addExtra(" ");
}
if (actor != null) {
msg.addExtra(actor.getName());
msg.addExtra(" ");
}
BlockData type = getBlockSet();
BlockData replaced = getBlockReplaced();
if (type == null || replaced == null) {
msg.addExtra("did an unknown block modification");
return new BaseComponent[] { msg };
}
// Process type details once for later use.
BaseComponent typeDetails = getTypeDetails(type, typeState, replaced, replacedState);
BaseComponent replacedDetails = getTypeDetails(replaced, replacedState);
if (type.getMaterial().equals(replaced.getMaterial()) || (type.getMaterial() == Material.CAKE && BukkitUtils.isCandleCake(replaced.getMaterial()))) {
if (BukkitUtils.isEmpty(type.getMaterial())) {
msg.addExtra(createTextComponentWithColor("did an unspecified action", INTERACT.getColor()));
} else if (ca != null) {
if (ca.itemStack == null) {
msg.addExtra(createTextComponentWithColor("looked inside ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
} else if (ca.remove) {
msg.addExtra(createTextComponentWithColor("took ", DESTROY.getColor()));
msg.addExtra(BukkitUtils.toString(ca.itemStack));
msg.addExtra(createTextComponentWithColor(" from ", DESTROY.getColor()));
msg.addExtra(prettyMaterial(type));
} else {
msg.addExtra(createTextComponentWithColor("put ", CREATE.getColor()));
msg.addExtra(BukkitUtils.toString(ca.itemStack));
msg.addExtra(createTextComponentWithColor(" into ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
}
} else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) {
if (((Waterlogged) type).isWaterlogged()) {
msg.addExtra(createTextComponentWithColor("waterlogged ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
} else {
msg.addExtra(createTextComponentWithColor("dried ", DESTROY.getColor()));
msg.addExtra(prettyMaterial(type));
}
} else if (BukkitUtils.isContainerBlock(type.getMaterial())) {
msg.addExtra(createTextComponentWithColor("opened ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
} else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) {
// Door, Trapdoor, Fence gate
msg.addExtra(createTextComponentWithColor(((Openable) type).isOpen() ? "opened " : "closed ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
} else if (type.getMaterial() == Material.LEVER && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) {
msg.addExtra(createTextComponentWithColor("switched ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(prettyState(((Switch) type).isPowered() ? " on" : " off"));
} else if (type instanceof Switch && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) {
msg.addExtra(createTextComponentWithColor("pressed ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
} else if (type.getMaterial() == Material.CAKE) {
msg.addExtra(createTextComponentWithColor("ate a piece of ", DESTROY.getColor()));
msg.addExtra(prettyMaterial(type));
} else if (type.getMaterial() == Material.NOTE_BLOCK) {
Note note = ((NoteBlock) type).getNote();
msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(" to ");
msg.addExtra(prettyState(note.getTone().name() + (note.isSharped() ? "#" : "")));
} else if (type.getMaterial() == Material.REPEATER) {
msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(" to ");
msg.addExtra(prettyState(((Repeater) type).getDelay()));
msg.addExtra(createTextComponentWithColor(" ticks delay", DEFAULT.getColor()));
} else if (type.getMaterial() == Material.COMPARATOR) {
msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(" to ");
msg.addExtra(prettyState(((Comparator) type).getMode()));
} else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) {
msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(" to ");
msg.addExtra(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal"));
} else if (type instanceof Lectern) {
msg.addExtra(createTextComponentWithColor("changed the book on a ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(" to");
msg.addExtra(prettyState(typeDetails));
} else if (type instanceof Powerable) {
msg.addExtra(createTextComponentWithColor("stepped on ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
} else if (type.getMaterial() == Material.TRIPWIRE) {
msg.addExtra(createTextComponentWithColor("ran into ", INTERACT.getColor()));
msg.addExtra(prettyMaterial(type));
} else if (type instanceof Sign || type instanceof WallSign) {
msg.addExtra(createTextComponentWithColor("edited a ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(createTextComponentWithColor(" to", CREATE.getColor()));
msg.addExtra(prettyState(typeDetails));
} else if (type instanceof Candle && ((Candle) type).getCandles() != ((Candle) replaced).getCandles()) {
msg.addExtra(createTextComponentWithColor("added a candle to ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
} else if ((type instanceof Candle || BukkitUtils.isCandleCake(type.getMaterial())) && ((Lightable) type).isLit() != ((Lightable) replaced).isLit()) {
if (((Lightable) type).isLit()) {
msg.addExtra(createTextComponentWithColor("lit a ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
} else {
msg.addExtra(createTextComponentWithColor("extinguished a ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
}
} else {
msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor()));
msg.addExtra(prettyMaterial(replaced));
msg.addExtra(prettyState(replacedDetails));
msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(prettyState(typeDetails));
}
} else if (BukkitUtils.isEmpty(type.getMaterial())) {
msg.addExtra(createTextComponentWithColor("destroyed ", DESTROY.getColor()));
msg.addExtra(prettyMaterial(replaced));
msg.addExtra(prettyState(replacedDetails));
} else if (BukkitUtils.isEmpty(replaced.getMaterial())) {
msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(prettyState(typeDetails));
} else {
msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor()));
msg.addExtra(prettyMaterial(replaced));
msg.addExtra(prettyState(replacedDetails));
msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor()));
msg.addExtra(prettyMaterial(type));
msg.addExtra(prettyState(typeDetails));
}
if (loc != null) {
msg.addExtra(" at ");
msg.addExtra(prettyLocation(loc, entry));
}
return new BaseComponent[] { msg };
}
public BlockData getBlockReplaced() {
return MaterialConverter.getBlockData(replacedMaterial, replacedData);
}
public BlockData getBlockSet() {
return MaterialConverter.getBlockData(typeMaterial, typeData);
}
@Override
public Location getLocation() {
return loc;
}
}

View File

@ -1,40 +1,59 @@
package de.diddiz.LogBlock;
import org.bukkit.Location;
import java.sql.ResultSet;
import java.sql.SQLException;
import static de.diddiz.util.LoggingUtil.checkText;
public class ChatMessage implements LookupCacheElement {
final long id, date;
final String playerName, message;
final Actor player;
public ChatMessage(Actor player, String message) {
id = 0;
date = System.currentTimeMillis() / 1000;
this.player = player;
this.message = checkText(message);
this.playerName = player == null ? null : player.getName();
}
public ChatMessage(ResultSet rs, QueryParams p) throws SQLException {
id = p.needId ? rs.getInt("id") : 0;
date = p.needDate ? rs.getTimestamp("date").getTime() : 0;
player = p.needPlayer ? new Actor(rs) : null;
playerName = p.needPlayer ? rs.getString("playername") : null;
message = p.needMessage ? rs.getString("message") : null;
}
@Override
public Location getLocation() {
return null;
}
@Override
public String getMessage() {
return (player != null ? "<" + player.getName() + "> " : "") + (message != null ? message : "");
}
}
package de.diddiz.LogBlock;
import static de.diddiz.LogBlock.util.LoggingUtil.checkText;
import static de.diddiz.LogBlock.util.MessagingUtil.brackets;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate;
import de.diddiz.LogBlock.util.MessagingUtil;
import de.diddiz.LogBlock.util.MessagingUtil.BracketType;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Location;
public class ChatMessage implements LookupCacheElement {
final long id, date;
final String playerName, message;
final Actor player;
public ChatMessage(Actor player, String message) {
id = 0;
date = System.currentTimeMillis() / 1000;
this.player = player;
this.message = checkText(message);
this.playerName = player == null ? null : player.getName();
}
public ChatMessage(ResultSet rs, QueryParams p) throws SQLException {
id = p.needId ? rs.getLong("id") : 0;
date = p.needDate ? rs.getTimestamp("date").getTime() : 0;
player = p.needPlayer ? new Actor(rs) : null;
playerName = p.needPlayer ? rs.getString("playername") : null;
message = p.needMessage ? rs.getString("message") : null;
}
@Override
public Location getLocation() {
return null;
}
@Override
public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent();
if (date > 0) {
msg.addExtra(prettyDate(date));
msg.addExtra(" ");
}
if (playerName != null) {
msg.addExtra(brackets(BracketType.ANGLE, MessagingUtil.createTextComponentWithColor(playerName, net.md_5.bungee.api.ChatColor.WHITE)));
msg.addExtra(" ");
}
if (message != null) {
for (BaseComponent messageComponent : TextComponent.fromLegacyText(message)) {
msg.addExtra(messageComponent);
}
}
return new BaseComponent[] { msg };
}
}

View File

@ -1,15 +1,15 @@
package de.diddiz.LogBlock;
import org.bukkit.inventory.ItemStack;
public class ChestAccess {
final ItemStack itemStack;
final boolean remove;
final int itemType;
public ChestAccess(ItemStack itemStack, boolean remove, int itemType) {
this.itemStack = itemStack;
this.remove = remove;
this.itemType = itemType;
}
}
package de.diddiz.LogBlock;
import org.bukkit.inventory.ItemStack;
public class ChestAccess {
public final ItemStack itemStack;
public final boolean remove;
public final int itemType;
public ChestAccess(ItemStack itemStack, boolean remove, int itemType) {
this.itemStack = itemStack;
this.remove = remove;
this.itemType = itemType;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,148 +1,147 @@
package de.diddiz.LogBlock;
import de.diddiz.util.Utils.ExtensionFilenameFilter;
import java.io.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Comparator;
import java.util.logging.Level;
import java.util.regex.Pattern;
import static de.diddiz.util.Utils.newline;
public class DumpedLogImporter implements Runnable {
private final LogBlock logblock;
DumpedLogImporter(LogBlock logblock) {
this.logblock = logblock;
}
@Override
public void run() {
final File[] imports = new File(logblock.getDataFolder(), "import").listFiles(new ExtensionFilenameFilter("sql"));
if (imports != null && imports.length > 0) {
logblock.getLogger().info("Found " + imports.length + " imports.");
Arrays.sort(imports, new ImportsComparator());
Connection conn = null;
try {
conn = logblock.getConnection();
if (conn == null) {
return;
}
conn.setAutoCommit(false);
final Statement st = conn.createStatement();
final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(logblock.getDataFolder(), "import/failed.txt")));
int successes = 0, errors = 0;
try {
for (final File sqlFile : imports) {
String line = null;
try {
logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ...");
// first try batch import the whole file
final BufferedReader reader = new BufferedReader(new FileReader(sqlFile));
int statements = 0;
while ((line = reader.readLine()) != null) {
if (line.endsWith(";")) {
line = line.substring(0, line.length() - 1);
}
if (!line.isEmpty()) {
statements++;
st.addBatch(line);
}
}
st.executeBatch();
conn.commit();
reader.close();
sqlFile.delete();
successes += statements;
logblock.getLogger().info("Successfully imported " + sqlFile.getName() + ".");
} catch (final Exception ignored) {
// if the batch import did not work, retry line by line
try {
final BufferedReader reader = new BufferedReader(new FileReader(sqlFile));
while ((line = reader.readLine()) != null) {
if (line.endsWith(";")) {
line = line.substring(0, line.length() - 1);
}
if (!line.isEmpty()) {
try {
st.execute(line);
successes++;
} catch (final SQLException ex) {
logblock.getLogger().severe("Error while importing: '" + line + "': " + ex.getMessage());
writer.write(line + newline);
errors++;
}
}
}
conn.commit();
reader.close();
sqlFile.delete();
logblock.getLogger().info("Successfully imported " + sqlFile.getName() + ".");
} catch (final Exception ex) {
logblock.getLogger().severe("Error while importing " + sqlFile.getName() + ": " + ex.getMessage());
errors++;
}
}
}
} finally {
writer.close();
}
st.close();
logblock.getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)");
} catch (final Exception ex) {
logblock.getLogger().log(Level.WARNING, "Error while importing: ", ex);
} finally {
if (conn != null) {
try {
conn.close();
} catch (final SQLException ex) {
}
}
}
}
}
private static class ImportsComparator implements Comparator<File> {
private final Pattern splitPattern = Pattern.compile("[\\-\\.]");
@Override
public int compare(File o1, File o2) {
String[] name1 = splitPattern.split(o1.getName());
String[] name2 = splitPattern.split(o2.getName());
if (name1.length > name2.length) {
return 1;
} else if (name1.length < name2.length) {
return -1;
}
for (int i = 0; i < name1.length; i++) {
String part1 = name1[i];
String part2 = name2[i];
if (part1.length() > 0 && part2.length() > 0) {
char first1 = part1.charAt(0);
char first2 = part2.charAt(0);
if (first1 >= '0' && first1 <= '9' && first2 >= '0' && first2 <= '9') {
try {
long long1 = Long.parseLong(part1);
long long2 = Long.parseLong(part2);
if (long1 == long2) {
continue;
}
return long1 > long2 ? 1 : -1;
} catch (NumberFormatException e) {
// fallthrough to string compare
}
}
}
int compareString = part1.compareTo(part2);
if (compareString != 0) {
return compareString;
}
}
return 0;
}
}
}
package de.diddiz.LogBlock;
import static de.diddiz.LogBlock.util.Utils.newline;
import de.diddiz.LogBlock.util.Utils.ExtensionFilenameFilter;
import java.io.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Comparator;
import java.util.logging.Level;
import java.util.regex.Pattern;
public class DumpedLogImporter implements Runnable {
private final LogBlock logblock;
DumpedLogImporter(LogBlock logblock) {
this.logblock = logblock;
}
@Override
public void run() {
final File[] imports = new File(logblock.getDataFolder(), "import").listFiles(new ExtensionFilenameFilter("sql"));
if (imports != null && imports.length > 0) {
logblock.getLogger().info("Found " + imports.length + " imports.");
Arrays.sort(imports, new ImportsComparator());
Connection conn = null;
try {
conn = logblock.getConnection();
if (conn == null) {
return;
}
conn.setAutoCommit(false);
final Statement st = conn.createStatement();
final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(logblock.getDataFolder(), "import/failed.txt")));
int successes = 0, errors = 0;
try {
for (final File sqlFile : imports) {
String line = null;
try {
logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ...");
// first try batch import the whole file
final BufferedReader reader = new BufferedReader(new FileReader(sqlFile));
int statements = 0;
while ((line = reader.readLine()) != null) {
if (line.endsWith(";")) {
line = line.substring(0, line.length() - 1);
}
if (!line.isEmpty()) {
statements++;
st.addBatch(line);
}
}
st.executeBatch();
conn.commit();
reader.close();
sqlFile.delete();
successes += statements;
logblock.getLogger().info("Successfully imported " + sqlFile.getName() + ".");
} catch (final Exception ignored) {
// if the batch import did not work, retry line by line
try {
final BufferedReader reader = new BufferedReader(new FileReader(sqlFile));
while ((line = reader.readLine()) != null) {
if (line.endsWith(";")) {
line = line.substring(0, line.length() - 1);
}
if (!line.isEmpty()) {
try {
st.execute(line);
successes++;
} catch (final SQLException ex) {
logblock.getLogger().severe("Error while importing: '" + line + "': " + ex.getMessage());
writer.write(line + newline);
errors++;
}
}
}
conn.commit();
reader.close();
sqlFile.delete();
logblock.getLogger().info("Successfully imported " + sqlFile.getName() + ".");
} catch (final Exception ex) {
logblock.getLogger().severe("Error while importing " + sqlFile.getName() + ": " + ex.getMessage());
errors++;
}
}
}
} finally {
writer.close();
}
st.close();
logblock.getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)");
} catch (final Exception ex) {
logblock.getLogger().log(Level.WARNING, "Error while importing: ", ex);
} finally {
if (conn != null) {
try {
conn.close();
} catch (final SQLException ex) {
}
}
}
}
}
private static class ImportsComparator implements Comparator<File> {
private final Pattern splitPattern = Pattern.compile("[\\-\\.]");
@Override
public int compare(File o1, File o2) {
String[] name1 = splitPattern.split(o1.getName());
String[] name2 = splitPattern.split(o2.getName());
if (name1.length > name2.length) {
return 1;
} else if (name1.length < name2.length) {
return -1;
}
for (int i = 0; i < name1.length; i++) {
String part1 = name1[i];
String part2 = name2[i];
if (part1.length() > 0 && part2.length() > 0) {
char first1 = part1.charAt(0);
char first2 = part2.charAt(0);
if (first1 >= '0' && first1 <= '9' && first2 >= '0' && first2 <= '9') {
try {
long long1 = Long.parseLong(part1);
long long2 = Long.parseLong(part2);
if (long1 == long2) {
continue;
}
return long1 > long2 ? 1 : -1;
} catch (NumberFormatException e) {
// fallthrough to string compare
}
}
}
int compareString = part1.compareTo(part2);
if (compareString != 0) {
return compareString;
}
}
return 0;
}
}
}

View File

@ -1,9 +1,20 @@
package de.diddiz.LogBlock;
import static de.diddiz.LogBlock.util.ActionColor.CREATE;
import static de.diddiz.LogBlock.util.ActionColor.DESTROY;
import static de.diddiz.LogBlock.util.ActionColor.INTERACT;
import static de.diddiz.LogBlock.util.MessagingUtil.createTextComponentWithColor;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyEntityType;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial;
import de.diddiz.LogBlock.util.Utils;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Location;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.ArmorStand;
@ -11,16 +22,14 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.util.Utils;
public class EntityChange implements LookupCacheElement {
public static enum EntityChangeType {
CREATE,
KILL,
MODIFY,
ADDEQUIP,
REMOVEEQUIP;
REMOVEEQUIP,
GET_STUNG;
private static EntityChangeType[] values = values();
@ -51,7 +60,7 @@ public class EntityChange implements LookupCacheElement {
}
public EntityChange(ResultSet rs, QueryParams p) throws SQLException {
id = p.needId ? rs.getInt("id") : 0;
id = p.needId ? rs.getLong("id") : 0;
date = p.needDate ? rs.getTimestamp("date").getTime() : 0;
loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null;
actor = p.needPlayer ? new Actor(rs) : null;
@ -64,53 +73,66 @@ public class EntityChange implements LookupCacheElement {
@Override
public String toString() {
final StringBuilder msg = new StringBuilder();
return BaseComponent.toPlainText(getLogMessage());
}
@Override
public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent();
if (date > 0) {
msg.append(Config.formatter.format(date)).append(" ");
msg.addExtra(prettyDate(date));
msg.addExtra(" ");
}
if (actor != null) {
msg.append(actor.getName()).append(" ");
msg.addExtra(actor.getName());
msg.addExtra(" ");
}
if (changeType == EntityChangeType.CREATE) {
msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor()));
} else if (changeType == EntityChangeType.KILL) {
boolean living = type != null && LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass());
msg.addExtra(createTextComponentWithColor(living ? "killed " : "destroyed ", DESTROY.getColor()));
} else if (changeType == EntityChangeType.ADDEQUIP) {
YamlConfiguration conf = Utils.deserializeYamlConfiguration(data);
ItemStack stack = conf == null ? null : conf.getItemStack("item");
if (stack == null) {
msg.addExtra(createTextComponentWithColor("added an item to ", CREATE.getColor()));
} else {
msg.addExtra(createTextComponentWithColor("added ", CREATE.getColor()));
msg.addExtra(prettyMaterial(stack.getType()));
msg.addExtra(" to ");
}
} else if (changeType == EntityChangeType.REMOVEEQUIP) {
YamlConfiguration conf = Utils.deserializeYamlConfiguration(data);
ItemStack stack = conf == null ? null : conf.getItemStack("item");
if (stack == null) {
msg.addExtra(createTextComponentWithColor("removed an item from ", DESTROY.getColor()));
} else {
msg.addExtra(createTextComponentWithColor("removed ", DESTROY.getColor()));
msg.addExtra(prettyMaterial(stack.getType()));
msg.addExtra(" from ");
}
} else if (changeType == EntityChangeType.MODIFY) {
msg.addExtra(createTextComponentWithColor("modified ", INTERACT.getColor()));
} else if (changeType == EntityChangeType.GET_STUNG) {
msg.addExtra(createTextComponentWithColor("got stung by ", DESTROY.getColor()));
} else {
msg.addExtra(createTextComponentWithColor("did an unknown action to ", INTERACT.getColor()));
}
if (type != null) {
boolean living = LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass());
if (changeType == EntityChangeType.CREATE) {
msg.append("created ");
} else if (changeType == EntityChangeType.KILL) {
msg.append(living ? "killed " : "destroyed ");
} else if (changeType == EntityChangeType.ADDEQUIP) {
YamlConfiguration conf = Utils.deserializeYamlConfiguration(data);
ItemStack stack = conf == null ? null : conf.getItemStack("item");
if (stack == null) {
msg.append("added an item to ");
} else {
msg.append("added " + stack.getType() + " to ");
}
} else if (changeType == EntityChangeType.REMOVEEQUIP) {
YamlConfiguration conf = Utils.deserializeYamlConfiguration(data);
ItemStack stack = conf == null ? null : conf.getItemStack("item");
if (stack == null) {
msg.append("removed an item from ");
} else {
msg.append("removed " + stack.getType() + " from ");
}
} else if (changeType == EntityChangeType.MODIFY) {
msg.append("modified ");
}
msg.append(type.name());
msg.addExtra(prettyEntityType(type));
} else {
msg.addExtra(prettyMaterial("an unknown entity"));
}
if (loc != null) {
msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ());
msg.addExtra(" at ");
msg.addExtra(prettyLocation(loc, entry));
}
return msg.toString();
return new BaseComponent[] { msg };
}
@Override
public Location getLocation() {
return loc;
}
@Override
public String getMessage() {
return toString();
}
}

View File

@ -16,7 +16,11 @@ public class EntityTypeConverter {
private static HashMap<EntityType, Integer> entityTypeToId = new HashMap<>();
private static int nextEntityTypeId;
public static int getOrAddEntityTypeId(EntityType entityType) {
public synchronized static Integer getExistingEntityTypeId(EntityType entityType) {
return entityType == null ? null : entityTypeToId.get(entityType);
}
public synchronized static int getOrAddEntityTypeId(EntityType entityType) {
Integer key = entityTypeToId.get(entityType);
int tries = 0;
while (key == null && tries < 10) {
@ -54,7 +58,7 @@ public class EntityTypeConverter {
return key.intValue();
}
public static EntityType getEntityType(int entityTypeId) {
public synchronized static EntityType getEntityType(int entityTypeId) {
return entityTypeId >= 0 && entityTypeId < idToEntityType.length ? idToEntityType[entityTypeId] : null;
}
@ -73,7 +77,7 @@ public class EntityTypeConverter {
}
}
public static void initializeEntityTypes(Connection connection) throws SQLException {
protected synchronized static void initializeEntityTypes(Connection connection) throws SQLException {
Statement smt = connection.createStatement();
ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-entitytypes`");
while (rs.next()) {
@ -93,7 +97,7 @@ public class EntityTypeConverter {
connection.close();
}
private synchronized static void internalAddEntityType(int key, EntityType entityType) {
private static void internalAddEntityType(int key, EntityType entityType) {
entityTypeToId.put(entityType, key);
int length = idToEntityType.length;
while (length <= key) {

View File

@ -1,13 +1,18 @@
package de.diddiz.LogBlock;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.util.BukkitUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import static de.diddiz.LogBlock.util.ActionColor.DESTROY;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial;
import de.diddiz.LogBlock.util.BukkitUtils;
import de.diddiz.LogBlock.util.MessagingUtil;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Location;
import org.bukkit.Material;
public class Kill implements LookupCacheElement {
final long id, date;
@ -25,7 +30,7 @@ public class Kill implements LookupCacheElement {
}
public Kill(ResultSet rs, QueryParams p) throws SQLException {
id = p.needId ? rs.getInt("id") : 0;
id = p.needId ? rs.getLong("id") : 0;
date = p.needDate ? rs.getTimestamp("date").getTime() : 0;
loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null;
killerName = p.needKiller ? rs.getString("killer") : null;
@ -35,19 +40,7 @@ public class Kill implements LookupCacheElement {
@Override
public String toString() {
final StringBuilder msg = new StringBuilder();
if (date > 0) {
msg.append(Config.formatter.format(date)).append(" ");
}
msg.append(killerName).append(" killed ").append(victimName);
if (loc != null) {
msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ());
}
if (weapon != 0) {
String weaponName = prettyItemName(MaterialConverter.getMaterial(weapon));
msg.append(" with " + weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " )
}
return msg.toString();
return BaseComponent.toPlainText(getLogMessage());
}
@Override
@ -56,14 +49,29 @@ public class Kill implements LookupCacheElement {
}
@Override
public String getMessage() {
return toString();
public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent();
if (date > 0) {
msg.addExtra(prettyDate(date));
msg.addExtra(" ");
}
msg.addExtra(MessagingUtil.createTextComponentWithColor(killerName + " killed ", DESTROY.getColor()));
msg.addExtra(new TextComponent(victimName));
if (loc != null) {
msg.addExtra(" at ");
msg.addExtra(prettyLocation(loc, entry));
}
if (weapon != 0) {
msg.addExtra(" with ");
msg.addExtra(prettyItemName(MaterialConverter.getMaterial(weapon)));
}
return new BaseComponent[] { msg };
}
public String prettyItemName(Material t) {
public TextComponent prettyItemName(Material t) {
if (t == null || BukkitUtils.isEmpty(t)) {
return "fist";
return prettyMaterial("fist");
}
return t.toString().replace('_', ' ').toLowerCase();
return prettyMaterial(t.toString().replace('_', ' '));
}
}

View File

@ -1,334 +1,386 @@
package de.diddiz.LogBlock;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.listeners.*;
import de.diddiz.LogBlock.questioner.Questioner;
import de.diddiz.util.BukkitUtils;
import de.diddiz.util.MySQLConnectionPool;
import de.diddiz.worldedit.WorldEditHelper;
import de.diddiz.worldedit.WorldEditLoggingHook;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import static de.diddiz.LogBlock.config.Config.*;
import static org.bukkit.Bukkit.getPluginManager;
public class LogBlock extends JavaPlugin {
private static LogBlock logblock = null;
private MySQLConnectionPool pool;
private Consumer consumer = null;
private CommandsHandler commandsHandler;
private boolean noDb = false, connected = true;
private PlayerInfoLogging playerInfoLogging;
private Questioner questioner;
private volatile boolean isCompletelyEnabled;
public static LogBlock getInstance() {
return logblock;
}
public boolean isCompletelyEnabled() {
return isCompletelyEnabled;
}
public Consumer getConsumer() {
return consumer;
}
public CommandsHandler getCommandsHandler() {
return commandsHandler;
}
@Override
public void onEnable() {
logblock = this;
BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run
final PluginManager pm = getPluginManager();
consumer = new Consumer(this);
try {
Config.load(this);
} catch (final Exception ex) {
getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage());
pm.disablePlugin(this);
return;
}
try {
getLogger().info("Connecting to " + user + "@" + url + "...");
pool = new MySQLConnectionPool(url, user, password, mysqlRequireSSL);
final Connection conn = getConnection(true);
if (conn == null) {
noDb = true;
return;
}
final Statement st = conn.createStatement();
final ResultSet rs = st.executeQuery("SHOW CHARACTER SET where charset='utf8mb4';");
if (rs.next()) {
Config.mb4 = true;
// Allegedly JDBC driver since 2010 hasn't needed this. I did.
st.executeQuery("SET NAMES utf8mb4;");
}
conn.close();
Updater updater = new Updater(this);
updater.checkTables();
MaterialConverter.initializeMaterials(getConnection());
MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry
EntityTypeConverter.initializeEntityTypes(getConnection());
if (updater.update()) {
load(this);
}
} catch (final NullPointerException ex) {
getLogger().log(Level.SEVERE, "Error while loading: ", ex);
} catch (final Exception ex) {
getLogger().log(Level.SEVERE, "Error while loading: " + ex.getMessage(), ex);
pm.disablePlugin(this);
return;
}
if (WorldEditHelper.hasWorldEdit()) {
new WorldEditLoggingHook(this).hook();
}
commandsHandler = new CommandsHandler(this);
getCommand("lb").setExecutor(commandsHandler);
if (enableAutoClearLog && autoClearLogDelay > 0) {
getServer().getScheduler().runTaskTimerAsynchronously(this, new AutoClearLog(this), 6000, autoClearLogDelay * 60 * 20);
}
new DumpedLogImporter(this).run();
registerEvents();
consumer.start();
for (final Tool tool : toolsByType.values()) {
if (pm.getPermission("logblock.tools." + tool.name) == null) {
final Permission perm = new Permission("logblock.tools." + tool.name, tool.permissionDefault);
pm.addPermission(perm);
}
}
questioner = new Questioner(this);
isCompletelyEnabled = true;
getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this));
}
private void registerEvents() {
final PluginManager pm = getPluginManager();
pm.registerEvents(new ToolListener(this), this);
pm.registerEvents(playerInfoLogging = new PlayerInfoLogging(this), this);
if (askRollbackAfterBan) {
pm.registerEvents(new BanListener(this), this);
}
if (isLogging(Logging.BLOCKPLACE)) {
pm.registerEvents(new BlockPlaceLogging(this), this);
}
if (isLogging(Logging.LAVAFLOW) || isLogging(Logging.WATERFLOW)) {
pm.registerEvents(new FluidFlowLogging(this), this);
}
if (isLogging(Logging.BLOCKBREAK)) {
pm.registerEvents(new BlockBreakLogging(this), this);
}
if (isLogging(Logging.SIGNTEXT)) {
pm.registerEvents(new SignChangeLogging(this), this);
}
if (isLogging(Logging.FIRE)) {
pm.registerEvents(new BlockBurnLogging(this), this);
}
if (isLogging(Logging.SNOWFORM)) {
pm.registerEvents(new SnowFormLogging(this), this);
}
if (isLogging(Logging.SNOWFADE)) {
pm.registerEvents(new SnowFadeLogging(this), this);
}
if (isLogging(Logging.CREEPEREXPLOSION) || isLogging(Logging.TNTEXPLOSION) || isLogging(Logging.GHASTFIREBALLEXPLOSION) || isLogging(Logging.ENDERDRAGON) || isLogging(Logging.MISCEXPLOSION)) {
pm.registerEvents(new ExplosionLogging(this), this);
}
if (isLogging(Logging.LEAVESDECAY)) {
pm.registerEvents(new LeavesDecayLogging(this), this);
}
if (isLogging(Logging.CHESTACCESS)) {
pm.registerEvents(new ChestAccessLogging(this), this);
}
if (isLogging(Logging.BLOCKBREAK) || isLogging(Logging.BLOCKPLACE) || isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT)
|| isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE)) {
pm.registerEvents(new InteractLogging(this), this);
}
if (isLogging(Logging.CREATURECROPTRAMPLE)) {
pm.registerEvents(new CreatureInteractLogging(this), this);
}
if (isLogging(Logging.KILL)) {
pm.registerEvents(new KillLogging(this), this);
}
if (isLogging(Logging.CHAT)) {
pm.registerEvents(new ChatLogging(this), this);
}
if (isLogging(Logging.ENDERMEN)) {
pm.registerEvents(new EndermenLogging(this), this);
}
if (isLogging(Logging.WITHER)) {
pm.registerEvents(new WitherLogging(this), this);
}
if (isLogging(Logging.NATURALSTRUCTUREGROW) || isLogging(Logging.BONEMEALSTRUCTUREGROW)) {
pm.registerEvents(new StructureGrowLogging(this), this);
}
if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD)) {
pm.registerEvents(new BlockSpreadLogging(this), this);
}
if (isLogging(Logging.DRAGONEGGTELEPORT)) {
pm.registerEvents(new DragonEggLogging(this), this);
}
if (Config.isLoggingAnyEntities()) {
if (!WorldEditHelper.hasFullWorldEdit()) {
getLogger().severe("No compatible WorldEdit found, entity logging will not work!");
} else {
pm.registerEvents(new AdvancedEntityLogging(this), this);
getLogger().info("Entity logging enabled!");
}
}
}
@Override
public void onDisable() {
isCompletelyEnabled = false;
getServer().getScheduler().cancelTasks(this);
if (consumer != null) {
if (logPlayerInfo && playerInfoLogging != null) {
for (final Player player : getServer().getOnlinePlayers()) {
playerInfoLogging.onPlayerQuit(player);
}
}
getLogger().info("Waiting for consumer ...");
consumer.shutdown();
if (consumer.getQueueSize() > 0) {
getLogger().info("Remaining queue size: " + consumer.getQueueSize() + ". Trying to write to a local file.");
try {
consumer.writeToFile();
getLogger().info("Successfully dumped queue.");
} catch (final FileNotFoundException ex) {
getLogger().info("Failed to write. Given up.");
}
}
}
if (pool != null) {
pool.close();
}
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
if (noDb) {
sender.sendMessage(ChatColor.RED + "No database connected. Check your MySQL user/pw and database for typos. Start/restart your MySQL server.");
}
return true;
}
public boolean hasPermission(CommandSender sender, String permission) {
return sender.hasPermission(permission);
}
public Connection getConnection() {
return getConnection(false);
}
public Connection getConnection(boolean testConnection) {
try {
final Connection conn = pool.getConnection();
if (!connected) {
getLogger().info("MySQL connection rebuild");
connected = true;
}
return conn;
} catch (final Exception ex) {
if (testConnection) {
getLogger().log(Level.SEVERE, "Could not connect to the Database! Please check your config! " + ex.getMessage());
} else if (connected) {
getLogger().log(Level.SEVERE, "Error while fetching connection: ", ex);
connected = false;
} else {
getLogger().log(Level.SEVERE, "MySQL connection lost", ex);
}
return null;
}
}
/**
* Returns a list of block changes based on the given query parameters, the query parameters
* are essentially programmatic versions of the parameters a player would pass
* to the logblock lookup command i.e /lb lookup <i>query-parameters</i>
*
* Note: this method directly calls a SQL query and is hence a slow blocking function, avoid running
* it on the main game thread
*
* @param params QueryParams that contains the needed columns (all other will be filled with default values) and the params. World is required.
* @return Returns a list of block changes based on the given query parameters
* @throws SQLException if a sql exception occurs while looking up the block changes
*/
public List<BlockChange> getBlockChanges(QueryParams params) throws SQLException {
final Connection conn = getConnection();
Statement state = null;
if (conn == null) {
throw new SQLException("No connection");
}
try {
state = conn.createStatement();
final ResultSet rs = state.executeQuery(params.getQuery());
final List<BlockChange> blockchanges = new ArrayList<BlockChange>();
while (rs.next()) {
blockchanges.add(new BlockChange(rs, params));
}
return blockchanges;
} finally {
if (state != null) {
state.close();
}
conn.close();
}
}
public int getCount(QueryParams params) throws SQLException {
if (params == null || params.world == null || !Config.isLogged(params.world)) {
throw new IllegalArgumentException("World is not logged: " + ((params == null || params.world == null) ? "null" : params.world.getName()));
}
final Connection conn = getConnection();
Statement state = null;
if (conn == null) {
throw new SQLException("No connection");
}
try {
state = conn.createStatement();
final QueryParams p = params.clone();
p.needCount = true;
final ResultSet rs = state.executeQuery(p.getQuery());
if (!rs.next()) {
return 0;
}
return rs.getInt(1);
} finally {
if (state != null) {
state.close();
}
conn.close();
}
}
@Override
public File getFile() {
return super.getFile();
}
public Questioner getQuestioner() {
return questioner;
}
}
package de.diddiz.LogBlock;
import de.diddiz.LogBlock.addons.worldguard.WorldGuardLoggingFlagsAddon;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.listeners.*;
import de.diddiz.LogBlock.questioner.Questioner;
import de.diddiz.LogBlock.util.BukkitUtils;
import de.diddiz.LogBlock.util.MySQLConnectionPool;
import de.diddiz.LogBlock.worldedit.WorldEditHelper;
import de.diddiz.LogBlock.worldedit.WorldEditLoggingHook;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import static de.diddiz.LogBlock.config.Config.*;
import static org.bukkit.Bukkit.getPluginManager;
public class LogBlock extends JavaPlugin {
private static LogBlock logblock = null;
private MySQLConnectionPool pool;
private Consumer consumer = null;
private CommandsHandler commandsHandler;
private boolean noDb = false, connected = true;
private PlayerInfoLogging playerInfoLogging;
private ScaffoldingLogging scaffoldingLogging;
private Questioner questioner;
private WorldGuardLoggingFlagsAddon worldGuardLoggingFlagsAddon;
private boolean isConfigLoaded;
private volatile boolean isCompletelyEnabled;
public static LogBlock getInstance() {
return logblock;
}
public boolean isCompletelyEnabled() {
return isCompletelyEnabled;
}
public Consumer getConsumer() {
return consumer;
}
public CommandsHandler getCommandsHandler() {
return commandsHandler;
}
@Override
public void onLoad() {
logblock = this;
BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run
try {
Config.load(this);
isConfigLoaded = true;
} catch (final Exception ex) {
getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage(), ex);
}
if (Config.worldGuardLoggingFlags) {
if (getServer().getPluginManager().getPlugin("WorldGuard") == null) {
getLogger().log(Level.SEVERE, "Invalid config! addons.worldguardLoggingFlags is set to true, but WorldGuard is not loaded.");
} else {
worldGuardLoggingFlagsAddon = new WorldGuardLoggingFlagsAddon(this);
worldGuardLoggingFlagsAddon.onPluginLoad();
}
}
}
@Override
public void onEnable() {
final PluginManager pm = getPluginManager();
if (!isConfigLoaded) {
pm.disablePlugin(this);
return;
}
consumer = new Consumer(this);
try {
getLogger().info("Connecting to " + user + "@" + url + "...");
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException ignored) {
Class.forName("com.mysql.jdbc.Driver");
}
pool = new MySQLConnectionPool(url, user, password, mysqlUseSSL, mysqlRequireSSL);
final Connection conn = getConnection(true);
if (conn == null) {
noDb = true;
return;
}
final Statement st = conn.createStatement();
try {
final ResultSet rs = st.executeQuery("SHOW CHARACTER SET where charset='utf8mb4';");
if (rs.next()) {
Config.mb4 = true;
// Allegedly JDBC driver since 2010 hasn't needed this. I did.
try {
st.executeUpdate("SET NAMES utf8mb4;");
} catch (Exception ex) {
getLogger().severe("could not set names to utf8mb4: " + ex.getMessage());
}
}
} catch (Exception ex) {
getLogger().severe("could not verify character set: " + ex.getMessage());
}
conn.close();
Updater updater = new Updater(this);
updater.checkTables();
MaterialConverter.initializeMaterials(getConnection());
MaterialConverter.getOrAddMaterialId(Material.AIR); // AIR must be the first entry
EntityTypeConverter.initializeEntityTypes(getConnection());
if (updater.update()) {
load(this);
}
} catch (final NullPointerException ex) {
getLogger().log(Level.SEVERE, "Error while loading: ", ex);
} catch (final Exception ex) {
getLogger().log(Level.SEVERE, "Error while loading: " + ex.getMessage(), ex);
pm.disablePlugin(this);
return;
}
if (WorldEditHelper.hasWorldEdit()) {
new WorldEditLoggingHook(this).hook();
}
commandsHandler = new CommandsHandler(this);
getCommand("lb").setExecutor(commandsHandler);
if (enableAutoClearLog && autoClearLogDelay > 0) {
getServer().getScheduler().runTaskTimerAsynchronously(this, new AutoClearLog(this), 6000, autoClearLogDelay * 60 * 20);
}
new DumpedLogImporter(this).run();
registerEvents();
consumer.start();
for (final Tool tool : toolsByType.values()) {
if (pm.getPermission("logblock.tools." + tool.name) == null) {
final Permission perm = new Permission("logblock.tools." + tool.name, tool.permissionDefault);
pm.addPermission(perm);
}
}
questioner = new Questioner(this);
if (worldGuardLoggingFlagsAddon != null) {
worldGuardLoggingFlagsAddon.onPluginEnable();
}
isCompletelyEnabled = true;
getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this));
}
private void registerEvents() {
final PluginManager pm = getPluginManager();
pm.registerEvents(new ToolListener(this), this);
pm.registerEvents(playerInfoLogging = new PlayerInfoLogging(this), this);
if (askRollbackAfterBan) {
pm.registerEvents(new BanListener(this), this);
}
if (isLogging(Logging.BLOCKPLACE)) {
pm.registerEvents(new BlockPlaceLogging(this), this);
}
if (isLogging(Logging.LAVAFLOW) || isLogging(Logging.WATERFLOW)) {
pm.registerEvents(new FluidFlowLogging(this), this);
}
if (isLogging(Logging.BLOCKBREAK)) {
pm.registerEvents(new BlockBreakLogging(this), this);
}
if (isLogging(Logging.SIGNTEXT)) {
pm.registerEvents(new SignChangeLogging(this), this);
}
if (isLogging(Logging.FIRE)) {
pm.registerEvents(new BlockBurnLogging(this), this);
}
if (isLogging(Logging.SNOWFORM)) {
pm.registerEvents(new SnowFormLogging(this), this);
}
if (isLogging(Logging.SNOWFADE)) {
pm.registerEvents(new SnowFadeLogging(this), this);
}
if (isLogging(Logging.SCAFFOLDING)) {
pm.registerEvents(scaffoldingLogging = new ScaffoldingLogging(this), this);
}
if (isLogging(Logging.CAULDRONINTERACT)) {
pm.registerEvents(new CauldronLogging(this), this);
}
if (isLogging(Logging.CREEPEREXPLOSION) || isLogging(Logging.TNTEXPLOSION) || isLogging(Logging.GHASTFIREBALLEXPLOSION) || isLogging(Logging.ENDERDRAGON) || isLogging(Logging.MISCEXPLOSION)) {
pm.registerEvents(new ExplosionLogging(this), this);
}
if (isLogging(Logging.LEAVESDECAY)) {
pm.registerEvents(new LeavesDecayLogging(this), this);
}
if (isLogging(Logging.CHESTACCESS)) {
pm.registerEvents(new ChestAccessLogging(this), this);
}
if (isLogging(Logging.BLOCKBREAK) || isLogging(Logging.BLOCKPLACE) || isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT)
|| isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE)) {
pm.registerEvents(new InteractLogging(this), this);
}
if (isLogging(Logging.CREATURECROPTRAMPLE)) {
pm.registerEvents(new CreatureInteractLogging(this), this);
}
if (isLogging(Logging.KILL)) {
pm.registerEvents(new KillLogging(this), this);
}
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
pm.registerEvents(new ChatLogging(this), this);
}
if (isLogging(Logging.ENDERMEN)) {
pm.registerEvents(new EndermenLogging(this), this);
}
if (isLogging(Logging.WITHER)) {
pm.registerEvents(new WitherLogging(this), this);
}
if (isLogging(Logging.NATURALSTRUCTUREGROW)) {
pm.registerEvents(new StructureGrowLogging(this), this);
}
if (isLogging(Logging.BONEMEALSTRUCTUREGROW)) {
pm.registerEvents(new BlockFertilizeLogging(this), this);
}
if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD) || isLogging(Logging.BAMBOOGROWTH) || isLogging(Logging.DRIPSTONEGROWTH) || isLogging(Logging.SCULKSPREAD)) {
pm.registerEvents(new BlockSpreadLogging(this), this);
}
if (isLogging(Logging.DRAGONEGGTELEPORT)) {
pm.registerEvents(new DragonEggLogging(this), this);
}
if (isLogging(Logging.LECTERNBOOKCHANGE)) {
pm.registerEvents(new LecternLogging(this), this);
}
if (isLogging(Logging.OXIDIZATION)) {
pm.registerEvents(new OxidizationLogging(this), this);
}
if (Config.isLoggingAnyEntities()) {
if (!WorldEditHelper.hasFullWorldEdit()) {
getLogger().severe("No compatible WorldEdit found, entity logging will not work!");
} else {
pm.registerEvents(new AdvancedEntityLogging(this), this);
getLogger().info("Entity logging enabled!");
}
}
}
@Override
public void onDisable() {
isCompletelyEnabled = false;
getServer().getScheduler().cancelTasks(this);
if (consumer != null) {
if (logPlayerInfo && playerInfoLogging != null) {
for (final Player player : getServer().getOnlinePlayers()) {
playerInfoLogging.onPlayerQuit(player);
}
}
getLogger().info("Waiting for consumer ...");
consumer.shutdown();
if (consumer.getQueueSize() > 0) {
getLogger().info("Remaining queue size: " + consumer.getQueueSize() + ". Trying to write to a local file.");
try {
consumer.writeToFile();
getLogger().info("Successfully dumped queue.");
} catch (final FileNotFoundException ex) {
getLogger().info("Failed to write. Given up.");
}
}
}
if (pool != null) {
pool.close();
}
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
if (noDb) {
sender.sendMessage(ChatColor.RED + "No database connected. Check your MySQL user/pw and database for typos. Start/restart your MySQL server.");
}
return true;
}
public boolean hasPermission(CommandSender sender, String permission) {
return sender.hasPermission(permission);
}
public Connection getConnection() {
return getConnection(false);
}
public Connection getConnection(boolean testConnection) {
try {
final Connection conn = pool.getConnection();
if (!connected) {
getLogger().info("MySQL connection rebuild");
connected = true;
}
return conn;
} catch (final Exception ex) {
if (testConnection) {
getLogger().log(Level.SEVERE, "Could not connect to the Database! Please check your config! " + ex.getMessage());
} else if (connected) {
getLogger().log(Level.SEVERE, "Error while fetching connection: ", ex);
connected = false;
} else {
getLogger().log(Level.SEVERE, "MySQL connection lost", ex);
}
return null;
}
}
/**
* Returns a list of block changes based on the given query parameters, the query parameters
* are essentially programmatic versions of the parameters a player would pass
* to the logblock lookup command i.e /lb lookup <i>query-parameters</i>
*
* Note: this method directly calls a SQL query and is hence a slow blocking function, avoid running
* it on the main game thread
*
* @param params QueryParams that contains the needed columns (all other will be filled with default values) and the params. World is required.
* @return Returns a list of block changes based on the given query parameters
* @throws SQLException if a sql exception occurs while looking up the block changes
*/
public List<BlockChange> getBlockChanges(QueryParams params) throws SQLException {
final Connection conn = getConnection();
Statement state = null;
if (conn == null) {
throw new SQLException("No connection");
}
try {
state = conn.createStatement();
final ResultSet rs = state.executeQuery(params.getQuery());
final List<BlockChange> blockchanges = new ArrayList<>();
while (rs.next()) {
blockchanges.add(new BlockChange(rs, params));
}
return blockchanges;
} finally {
if (state != null) {
state.close();
}
conn.close();
}
}
public int getCount(QueryParams params) throws SQLException {
if (params == null || params.world == null || !Config.isLogged(params.world)) {
throw new IllegalArgumentException("World is not logged: " + ((params == null || params.world == null) ? "null" : params.world.getName()));
}
final Connection conn = getConnection();
Statement state = null;
if (conn == null) {
throw new SQLException("No connection");
}
try {
state = conn.createStatement();
final QueryParams p = params.clone();
p.needCount = true;
final ResultSet rs = state.executeQuery(p.getQuery());
if (!rs.next()) {
return 0;
}
return rs.getInt(1);
} finally {
if (state != null) {
state.close();
}
conn.close();
}
}
@Override
public File getFile() {
return super.getFile();
}
public Questioner getQuestioner() {
return questioner;
}
public ScaffoldingLogging getScaffoldingLogging() {
return scaffoldingLogging;
}
}

View File

@ -1,14 +1,60 @@
package de.diddiz.LogBlock;
public enum Logging {
BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT, TNTEXPLOSION(true), CREEPEREXPLOSION(true),
GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION(true), FIRE(true), LEAVESDECAY,
LAVAFLOW, WATERFLOW, CHESTACCESS, KILL, CHAT, SNOWFORM, SNOWFADE, DOORINTERACT,
SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT,
PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE,
NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD,
WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, WORLDEDIT, TNTMINECARTEXPLOSION(true),
ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true), DRAGONEGGTELEPORT(true), DAYLIGHTDETECTORINTERACT;
BLOCKPLACE(true),
BLOCKBREAK(true),
SIGNTEXT(true),
TNTEXPLOSION(true),
CREEPEREXPLOSION(true),
GHASTFIREBALLEXPLOSION(true),
ENDERDRAGON(true),
MISCEXPLOSION(true),
FIRE(true),
LEAVESDECAY,
LAVAFLOW,
WATERFLOW,
CHESTACCESS,
KILL,
CHAT,
SNOWFORM,
SNOWFADE,
DOORINTERACT,
SWITCHINTERACT,
CAKEEAT,
ENDERMEN,
NOTEBLOCKINTERACT,
DIODEINTERACT,
COMPARATORINTERACT,
PRESUREPLATEINTERACT,
TRIPWIREINTERACT,
CAULDRONINTERACT(true),
CREATURECROPTRAMPLE,
CROPTRAMPLE,
NATURALSTRUCTUREGROW,
GRASSGROWTH,
MYCELIUMSPREAD,
VINEGROWTH,
DRIPSTONEGROWTH,
MUSHROOMSPREAD,
BAMBOOGROWTH,
WITHER(true),
WITHER_SKULL(true),
BONEMEALSTRUCTUREGROW,
WORLDEDIT,
TNTMINECARTEXPLOSION(true),
ENDERCRYSTALEXPLOSION(true),
BEDEXPLOSION(true),
DRAGONEGGTELEPORT(true),
DAYLIGHTDETECTORINTERACT,
LECTERNBOOKCHANGE(true),
SCAFFOLDING(true),
OXIDIZATION,
SCULKSPREAD(true),
SHULKER_BOX_CONTENT,
RESPAWNANCHOREXPLOSION(true),
PLAYER_COMMANDS,
COMMANDBLOCK_COMMANDS,
CONSOLE_COMMANDS;
public static final int length = Logging.values().length;
private final boolean defaultEnabled;

View File

@ -1,9 +1,18 @@
package de.diddiz.LogBlock;
import org.bukkit.Location;
public interface LookupCacheElement {
public Location getLocation();
public String getMessage();
}
package de.diddiz.LogBlock;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.Location;
public interface LookupCacheElement {
public Location getLocation();
public default BaseComponent[] getLogMessage() {
return getLogMessage(-1);
}
public BaseComponent[] getLogMessage(int entry);
public default int getNumChanges() {
return 1;
}
}

View File

@ -1,40 +1,40 @@
package de.diddiz.LogBlock;
import de.diddiz.LogBlock.QueryParams.BlockChangeType;
import de.diddiz.LogBlock.QueryParams.SummarizationMode;
import java.sql.ResultSet;
import java.sql.SQLException;
public class LookupCacheElementFactory {
private final QueryParams params;
private final float spaceFactor;
public LookupCacheElementFactory(QueryParams params, float spaceFactor) {
this.params = params;
this.spaceFactor = spaceFactor;
}
public LookupCacheElement getLookupCacheElement(ResultSet rs) throws SQLException {
if (params.bct == BlockChangeType.CHAT) {
return new ChatMessage(rs, params);
}
if (params.bct == BlockChangeType.KILLS) {
if (params.sum == SummarizationMode.NONE) {
return new Kill(rs, params);
} else if (params.sum == SummarizationMode.PLAYERS) {
return new SummedKills(rs, params, spaceFactor);
}
}
if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) {
if (params.sum == SummarizationMode.NONE) {
return new EntityChange(rs, params);
}
return new SummedEntityChanges(rs, params, spaceFactor);
}
if (params.sum == SummarizationMode.NONE) {
return new BlockChange(rs, params);
}
return new SummedBlockChanges(rs, params, spaceFactor);
}
}
package de.diddiz.LogBlock;
import de.diddiz.LogBlock.QueryParams.BlockChangeType;
import de.diddiz.LogBlock.QueryParams.SummarizationMode;
import java.sql.ResultSet;
import java.sql.SQLException;
public class LookupCacheElementFactory {
private final QueryParams params;
private final float spaceFactor;
public LookupCacheElementFactory(QueryParams params, float spaceFactor) {
this.params = params;
this.spaceFactor = spaceFactor;
}
public LookupCacheElement getLookupCacheElement(ResultSet rs) throws SQLException {
if (params.bct == BlockChangeType.CHAT) {
return new ChatMessage(rs, params);
}
if (params.bct == BlockChangeType.KILLS) {
if (params.sum == SummarizationMode.NONE) {
return new Kill(rs, params);
} else if (params.sum == SummarizationMode.PLAYERS) {
return new SummedKills(rs, params, spaceFactor);
}
}
if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) {
if (params.sum == SummarizationMode.NONE) {
return new EntityChange(rs, params);
}
return new SummedEntityChanges(rs, params, spaceFactor);
}
if (params.sum == SummarizationMode.NONE) {
return new BlockChange(rs, params);
}
return new SummedBlockChanges(rs, params, spaceFactor);
}
}

View File

@ -11,7 +11,6 @@ import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
public class MaterialConverter {
@ -22,7 +21,7 @@ public class MaterialConverter {
private static String[] idToBlockState = new String[10];
private static HashMap<String, Integer> blockStateToID = new HashMap<>();
private static int nextBlockStateId;
private static HashMap<String, Material> materialKeyToMaterial = new HashMap<>();
static {
@ -31,16 +30,27 @@ public class MaterialConverter {
}
}
public static int getOrAddMaterialId(NamespacedKey nameSpaceKey) {
return getOrAddMaterialId(nameSpaceKey.toString());
public synchronized static Integer getExistingMaterialId(BlockData blockData) {
return blockData == null ? null : getExistingMaterialId(blockData.getMaterial());
}
public static int getOrAddMaterialId(String blockDataString) {
String materialString = blockDataString;
int dataPart = blockDataString.indexOf("[");
if (dataPart >= 0) {
materialString = blockDataString.substring(0, dataPart);
public synchronized static Integer getExistingMaterialId(Material material) {
if (material == null) {
return null;
}
String materialString = material.getKey().toString();
return materialToID.get(materialString);
}
public synchronized static int getOrAddMaterialId(BlockData blockData) {
return getOrAddMaterialId(blockData == null ? Material.AIR : blockData.getMaterial());
}
public synchronized static int getOrAddMaterialId(Material material) {
if (material == null) {
material = Material.AIR;
}
String materialString = material.getKey().toString();
Integer key = materialToID.get(materialString);
int tries = 0;
while (key == null && tries < 10) {
@ -78,7 +88,24 @@ public class MaterialConverter {
return key.intValue();
}
public static int getOrAddBlockStateId(String blockDataString) {
public synchronized static Integer getExistingBlockStateId(BlockData blockData) {
if (blockData == null) {
return -1;
}
String blockDataString = blockData.getAsString();
int dataPart = blockDataString.indexOf("[");
if (dataPart < 0) {
return -1;
}
String materialString = blockDataString.substring(dataPart);
return blockStateToID.get(materialString);
}
public synchronized static int getOrAddBlockStateId(BlockData blockData) {
if (blockData == null) {
return -1;
}
String blockDataString = blockData.getAsString();
int dataPart = blockDataString.indexOf("[");
if (dataPart < 0) {
return -1;
@ -121,13 +148,13 @@ public class MaterialConverter {
return key.intValue();
}
public static BlockData getBlockData(int materialId, int blockStateId) {
public synchronized static BlockData getBlockData(int materialId, int blockStateId) {
String material = materialId >= 0 && materialId < idToMaterial.length ? idToMaterial[materialId] : null;
if (material == null) {
return null;
}
if (blockStateId >= 0 && blockStateId < idToBlockState.length && idToBlockState[blockStateId] != null) {
material = material + idToBlockState[blockStateId];
material = material + updateBlockState(material, idToBlockState[blockStateId]);
}
try {
return Bukkit.createBlockData(material);
@ -141,7 +168,7 @@ public class MaterialConverter {
}
}
public static Material getMaterial(int materialId) {
public synchronized static Material getMaterial(int materialId) {
return materialId >= 0 && materialId < idToMaterial.length ? materialKeyToMaterial.get(idToMaterial[materialId]) : null;
}
@ -160,7 +187,7 @@ public class MaterialConverter {
}
}
public static void initializeMaterials(Connection connection) throws SQLException {
protected synchronized static void initializeMaterials(Connection connection) throws SQLException {
Statement smt = connection.createStatement();
ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-materials`");
while (rs.next()) {
@ -180,7 +207,7 @@ public class MaterialConverter {
connection.close();
}
private synchronized static void internalAddMaterial(int key, String materialString) {
private static void internalAddMaterial(int key, String materialString) {
materialToID.put(materialString, key);
int length = idToMaterial.length;
while (length <= key) {
@ -195,7 +222,7 @@ public class MaterialConverter {
}
}
private synchronized static void internalAddBlockState(int key, String materialString) {
private static void internalAddBlockState(int key, String materialString) {
blockStateToID.put(materialString, key);
int length = idToBlockState.length;
while (length <= key) {
@ -209,4 +236,21 @@ public class MaterialConverter {
nextBlockStateId = key + 1;
}
}
private static String updateBlockState(String material, String blockState) {
// since 1.16
if (material.endsWith("_wall")) {
if (blockState.contains("east=false") || blockState.contains("east=true")) {
blockState = blockState.replace("east=false", "east=none");
blockState = blockState.replace("west=false", "west=none");
blockState = blockState.replace("north=false", "north=none");
blockState = blockState.replace("south=false", "south=none");
blockState = blockState.replace("east=true", "east=low");
blockState = blockState.replace("west=true", "west=low");
blockState = blockState.replace("north=true", "north=low");
blockState = blockState.replace("south=true", "south=low");
}
}
return blockState;
}
}

View File

@ -1,24 +1,27 @@
package de.diddiz.LogBlock;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.util.BukkitUtils;
import de.diddiz.util.Utils;
import de.diddiz.worldedit.CuboidRegion;
import de.diddiz.worldedit.WorldEditHelper;
import de.diddiz.LogBlock.util.BukkitUtils;
import de.diddiz.LogBlock.util.CuboidRegion;
import de.diddiz.LogBlock.util.SqlUtil;
import de.diddiz.LogBlock.util.Utils;
import de.diddiz.LogBlock.worldedit.WorldEditHelper;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.regex.Pattern;
import static de.diddiz.LogBlock.Session.getSession;
import static de.diddiz.LogBlock.config.Config.*;
import static de.diddiz.util.BukkitUtils.friendlyWorldname;
import static de.diddiz.util.Utils.*;
import static de.diddiz.LogBlock.util.BukkitUtils.friendlyWorldname;
import static de.diddiz.LogBlock.util.Utils.*;
public final class QueryParams implements Cloneable {
private static final HashMap<String, Integer> keywords = new HashMap<>();
@ -62,17 +65,16 @@ public final class QueryParams implements Cloneable {
public int limit = -1, before = 0, since = 0, radius = -1;
public Location loc = null;
public Order order = Order.DESC;
public List<String> players = new ArrayList<String>();
public List<String> killers = new ArrayList<String>();
public List<String> victims = new ArrayList<String>();
public List<String> players = new ArrayList<>();
public List<String> killers = new ArrayList<>();
public List<String> victims = new ArrayList<>();
public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksEntitiesMode = false, prepareToolQuery = false, silent = false, noForcedLimit = false;
public boolean forceReplace = false, noCache = false;
public CuboidRegion sel = null;
public SummarizationMode sum = SummarizationMode.NONE;
public List<Material> types = new ArrayList<Material>();
public List<Integer> typeIds = new ArrayList<Integer>();
public List<EntityType> entityTypes = new ArrayList<EntityType>();
public List<Integer> entityTypeIds = new ArrayList<Integer>();
public List<Material> types = new ArrayList<>();
public List<Tag<Material>> typeTags = new ArrayList<>();
public List<EntityType> entityTypes = new ArrayList<>();
public World world = null;
public String match = null;
public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayerId = false, needPlayer = false, needCoords = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false;
@ -273,7 +275,7 @@ public final class QueryParams implements Cloneable {
if (needType) {
select += "entitytypeid, action, ";
}
if(needData) {
if (needData) {
select += "entityid, entityuuid, data, ";
}
}
@ -291,21 +293,26 @@ public final class QueryParams implements Cloneable {
}
if (bct == BlockChangeType.KILLS) {
if (sum == SummarizationMode.PLAYERS) {
return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit();
return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable()
+ "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit();
}
throw new IllegalStateException("Invalid summarization for kills");
}
if (bct == BlockChangeType.ENTITIES || bct == BlockChangeType.ENTITIES_CREATED || bct == BlockChangeType.ENTITIES_KILLED) {
if (sum == SummarizationMode.TYPES) {
return "SELECT entitytypeid, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT entitytypeid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY entitytypeid) UNION (SELECT entitytypeid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_KILLED) + "GROUP BY entitytypeid)) AS t GROUP BY entitytypeid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
return "SELECT entitytypeid, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT entitytypeid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY entitytypeid) UNION (SELECT entitytypeid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_KILLED)
+ "GROUP BY entitytypeid)) AS t GROUP BY entitytypeid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
} else {
return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_KILLED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_KILLED)
+ "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
}
}
if (sum == SummarizationMode.TYPES) {
return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED)
+ "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
} else {
return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.DESTROYED)
+ "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
}
}
@ -335,14 +342,17 @@ public final class QueryParams implements Cloneable {
title.append("entity changes ");
}
} else {
if (!types.isEmpty()) {
if (!types.isEmpty() || !typeTags.isEmpty()) {
if (excludeBlocksEntitiesMode) {
title.append("all blocks except ");
}
final String[] blocknames = new String[types.size()];
final String[] blocknames = new String[types.size() + typeTags.size()];
for (int i = 0; i < types.size(); i++) {
blocknames[i] = types.get(i).name();
}
for (int i = 0; i < typeTags.size(); i++) {
blocknames[i + types.size()] = "#" + typeTags.get(i).getKey().getKey().toUpperCase();
}
title.append(listing(blocknames, ", ", " and ")).append(" ");
} else {
title.append("block ");
@ -416,9 +426,9 @@ public final class QueryParams implements Cloneable {
if (match != null && match.length() > 0) {
final boolean unlike = match.startsWith("-");
if (match.length() > 3 && !unlike || match.length() > 4) {
where.append("MATCH (message) AGAINST ('").append(match).append("' IN BOOLEAN MODE) AND ");
where.append("MATCH (message) AGAINST ('").append(SqlUtil.escapeString(match)).append("' IN BOOLEAN MODE) AND ");
} else {
where.append("message ").append(unlike ? "NOT " : "").append("LIKE '%").append(unlike ? match.substring(1) : match).append("%' AND ");
where.append("message ").append(unlike ? "NOT " : "").append("LIKE '%").append(SqlUtil.escapeString(unlike ? match.substring(1) : match, true)).append("%' AND ");
}
}
} else if (blockChangeType == BlockChangeType.KILLS) {
@ -426,19 +436,19 @@ public final class QueryParams implements Cloneable {
if (!excludePlayersMode) {
where.append('(');
for (final String killerName : players) {
where.append("killers.playername = '").append(killerName).append("' OR ");
where.append("killers.playername = '").append(SqlUtil.escapeString(killerName)).append("' OR ");
}
for (final String victimName : players) {
where.append("victims.playername = '").append(victimName).append("' OR ");
where.append("victims.playername = '").append(SqlUtil.escapeString(victimName)).append("' OR ");
}
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else {
for (final String killerName : players) {
where.append("killers.playername != '").append(killerName).append("' AND ");
where.append("killers.playername != '").append(SqlUtil.escapeString(killerName)).append("' AND ");
}
for (final String victimName : players) {
where.append("victims.playername != '").append(victimName).append("' AND ");
where.append("victims.playername != '").append(SqlUtil.escapeString(victimName)).append("' AND ");
}
}
}
@ -447,13 +457,13 @@ public final class QueryParams implements Cloneable {
if (!excludeKillersMode) {
where.append('(');
for (final String killerName : killers) {
where.append("killers.playername = '").append(killerName).append("' OR ");
where.append("killers.playername = '").append(SqlUtil.escapeString(killerName)).append("' OR ");
}
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else {
for (final String killerName : killers) {
where.append("killers.playername != '").append(killerName).append("' AND ");
where.append("killers.playername != '").append(SqlUtil.escapeString(killerName)).append("' AND ");
}
}
}
@ -473,6 +483,7 @@ public final class QueryParams implements Cloneable {
}
}
} else if (blockChangeType == BlockChangeType.ENTITIES || blockChangeType == BlockChangeType.ENTITIES_CREATED || blockChangeType == BlockChangeType.ENTITIES_KILLED) {
Set<Integer> entityTypeIds = getEntityTypeIds();
if (!entityTypeIds.isEmpty()) {
if (excludeBlocksEntitiesMode) {
where.append("NOT ");
@ -491,6 +502,7 @@ public final class QueryParams implements Cloneable {
where.append("action = " + EntityChange.EntityChangeType.KILL.ordinal() + " AND ");
}
} else {
Set<Integer> typeIds = getTypeIds();
switch (blockChangeType) {
case ALL:
if (!typeIds.isEmpty()) {
@ -574,22 +586,20 @@ public final class QueryParams implements Cloneable {
break;
}
}
if(blockChangeType != BlockChangeType.CHAT) {
if (blockChangeType != BlockChangeType.CHAT) {
if (loc != null) {
if (radius == 0) {
compileLocationQuery(
where,
loc.getBlockX(), loc.getBlockX(),
loc.getBlockY(), loc.getBlockY(),
loc.getBlockZ(), loc.getBlockZ()
);
loc.getBlockZ(), loc.getBlockZ());
} else if (radius > 0) {
compileLocationQuery(
where,
loc.getBlockX() - radius + 1, loc.getBlockX() + radius - 1,
loc.getBlockY() - radius + 1, loc.getBlockY() + radius - 1,
loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1
);
loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1);
}
} else if (sel != null) {
@ -597,21 +607,20 @@ public final class QueryParams implements Cloneable {
where,
sel.getMinimumPoint().getBlockX(), sel.getMaximumPoint().getBlockX(),
sel.getMinimumPoint().getBlockY(), sel.getMaximumPoint().getBlockY(),
sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ()
);
sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ());
}
}
if (!players.isEmpty() && sum != SummarizationMode.PLAYERS && blockChangeType != BlockChangeType.KILLS) {
if (!excludePlayersMode) {
where.append('(');
for (final String playerName : players) {
where.append("playername = '").append(playerName).append("' OR ");
where.append("playername = '").append(SqlUtil.escapeString(playerName)).append("' OR ");
}
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else {
for (final String playerName : players) {
where.append("playername != '").append(playerName).append("' AND ");
where.append("playername != '").append(SqlUtil.escapeString(playerName)).append("' AND ");
}
}
}
@ -682,16 +691,20 @@ public final class QueryParams implements Cloneable {
if (values.length < 1) {
throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
}
for (final String playerName : values) {
for (String playerName : values) {
if (playerName.length() > 0) {
if (playerName.contains("!")) {
if (playerName.startsWith("!")) {
playerName = playerName.substring(1);
excludePlayersMode = true;
if (playerName.isEmpty()) {
continue;
}
}
if (playerName.contains("\"")) {
players.add(playerName.replaceAll("[^a-zA-Z0-9_]", ""));
players.add(playerName.replace("\"", ""));
} else {
final Player matches = logblock.getServer().getPlayerExact(playerName);
players.add(matches != null ? matches.getName() : playerName.replaceAll("[^a-zA-Z0-9_]", ""));
players.add(matches != null ? matches.getName() : playerName.replace("\\\"", ""));
}
}
}
@ -748,7 +761,6 @@ public final class QueryParams implements Cloneable {
throw new IllegalArgumentException("No material matching: '" + weaponName + "'");
}
types.add(mat);
typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey()));
}
needWeapon = true;
} else if (param.equals("block") || param.equals("type")) {
@ -760,13 +772,50 @@ public final class QueryParams implements Cloneable {
excludeBlocksEntitiesMode = true;
blockName = blockName.substring(1);
}
final Material mat = Material.matchMaterial(blockName);
if (mat == null) {
throw new IllegalArgumentException("No material matching: '" + blockName + "'");
if (blockName.startsWith("#")) {
String tagName = blockName.substring(1).toLowerCase();
Tag<Material> tag = logblock.getServer().getTag(Tag.REGISTRY_BLOCKS, NamespacedKey.minecraft(tagName), Material.class);
if (tag == null || tag.getValues().isEmpty()) {
tag = logblock.getServer().getTag(Tag.REGISTRY_ITEMS, NamespacedKey.minecraft(tagName), Material.class);
if (tag == null || tag.getValues().isEmpty()) {
throw new IllegalArgumentException("No block tag matching: '" + blockName + "'");
}
}
typeTags.add(tag);
} else if (blockName.contains("*")) {
StringBuilder sb = new StringBuilder();
for (int ci = 0; ci < blockName.length(); ci++) {
char c = blockName.charAt(ci);
if (!Character.isAlphabetic(c)) {
if (c == '*') {
sb.append('.');
} else {
sb.append('\\');
}
}
sb.append(c);
}
String blockNamePattern = sb.toString();
Pattern pattern = Pattern.compile(blockNamePattern, Pattern.CASE_INSENSITIVE);
ArrayList<Material> matched = new ArrayList<>();
for (Material mat : Material.values()) {
if (pattern.matcher(mat.name()).matches()) {
matched.add(mat);
}
}
if (matched.isEmpty()) {
throw new IllegalArgumentException("No material matching: '" + blockName + "'");
}
for (Material mat : matched) {
types.add(mat);
}
} else {
final Material mat = Material.matchMaterial(blockName);
if (mat == null) {
throw new IllegalArgumentException("No material matching: '" + blockName + "'");
}
types.add(mat);
}
types.add(mat);
typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey()));
}
} else if (param.equals("area")) {
if (player == null && !prepareToolQuery && loc == null) {
@ -790,11 +839,7 @@ public final class QueryParams implements Cloneable {
if (player == null) {
throw new IllegalArgumentException("You have to be a player to use selection");
}
if (WorldEditHelper.hasWorldEdit()) {
setSelection(CuboidRegion.fromPlayerSelection(player));
} else {
throw new IllegalArgumentException("WorldEdit not found!");
}
setSelection(WorldEditHelper.getSelectedRegion(player));
} else if (param.equals("time") || param.equals("since")) {
since = values.length > 0 ? parseTimeSpec(values) : defaultTime;
if (since == -1) {
@ -812,6 +857,9 @@ public final class QueryParams implements Cloneable {
if (values[0].startsWith("p")) {
sum = SummarizationMode.PLAYERS;
} else if (values[0].startsWith("b") || values[0].startsWith("e")) {
if (values[0].startsWith("e")) {
bct = BlockChangeType.ENTITIES;
}
sum = SummarizationMode.TYPES;
} else if (values[0].startsWith("n")) {
sum = SummarizationMode.NONE;
@ -844,7 +892,6 @@ public final class QueryParams implements Cloneable {
throw new IllegalArgumentException("No entity type matching: '" + entityTypeName + "'");
}
entityTypes.add(entityType);
entityTypeIds.add(EntityTypeConverter.getOrAddEntityTypeId(entityType));
}
}
} else if (param.equals("all")) {
@ -882,7 +929,7 @@ public final class QueryParams implements Cloneable {
if (values.length == 0) {
throw new IllegalArgumentException("No arguments for '" + param + "'");
}
match = mysqlTextEscape(join(values, " "));
match = join(values, " ");
} else if (param.equals("loc") || param.equals("location")) {
final String[] vectors = values.length == 1 ? values[0].split(":") : values;
if (vectors.length != 3) {
@ -929,7 +976,7 @@ public final class QueryParams implements Cloneable {
}
}
if (bct == BlockChangeType.CHAT) {
if (!Config.isLogging(Logging.CHAT)) {
if (!(isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS))) {
throw new IllegalArgumentException("Chat is not logged");
}
if (sum != SummarizationMode.NONE) {
@ -959,13 +1006,12 @@ public final class QueryParams implements Cloneable {
public QueryParams clone() {
try {
final QueryParams params = (QueryParams) super.clone();
params.players = new ArrayList<String>(players);
params.killers = new ArrayList<String>(killers);
params.victims = new ArrayList<String>(victims);
params.typeIds = new ArrayList<Integer>(typeIds);
params.types = new ArrayList<Material>(types);
params.entityTypeIds = new ArrayList<Integer>(entityTypeIds);
params.entityTypes = new ArrayList<EntityType>(entityTypes);
params.players = new ArrayList<>(players);
params.killers = new ArrayList<>(killers);
params.victims = new ArrayList<>(victims);
params.types = new ArrayList<>(types);
params.typeTags = new ArrayList<>(typeTags);
params.entityTypes = new ArrayList<>(entityTypes);
params.loc = loc == null ? null : loc.clone();
params.sel = sel == null ? null : sel.clone();
return params;
@ -974,6 +1020,48 @@ public final class QueryParams implements Cloneable {
}
}
private Set<Integer> getTypeIds() {
HashSet<Integer> typeIds = new HashSet<>();
for (Material type : types) {
if (type != null) {
Integer id = MaterialConverter.getExistingMaterialId(type);
if (id != null) {
typeIds.add(id);
}
}
}
for (Tag<Material> tag : typeTags) {
if (tag != null) {
for (Material type : tag.getValues()) {
Integer id = MaterialConverter.getExistingMaterialId(type);
if (id != null) {
typeIds.add(id);
}
}
}
}
// add invalid id, so the type list is not ignored
if ((!types.isEmpty() || !typeTags.isEmpty()) && typeIds.isEmpty()) {
typeIds.add(-1);
}
return typeIds;
}
private Set<Integer> getEntityTypeIds() {
HashSet<Integer> typeIds = new HashSet<>();
for (EntityType type : entityTypes) {
Integer id = EntityTypeConverter.getExistingEntityTypeId(type);
if (id != null) {
typeIds.add(id);
}
}
// add invalid id, so the type list is not ignored
if (!entityTypes.isEmpty() && typeIds.isEmpty()) {
typeIds.add(-1);
}
return typeIds;
}
private static String[] getValues(List<String> args, int offset, int minParams) {
// The variable i will store the last value's index
int i;
@ -1008,9 +1096,8 @@ public final class QueryParams implements Cloneable {
killers.addAll(p.killers);
victims.addAll(p.victims);
excludePlayersMode = p.excludePlayersMode;
typeIds.addAll(p.typeIds);
types.addAll(p.types);
entityTypeIds.addAll(p.entityTypeIds);
typeTags.addAll(p.typeTags);
entityTypes.addAll(p.entityTypes);
loc = p.loc == null ? null : p.loc.clone();
radius = p.radius;
@ -1028,14 +1115,26 @@ public final class QueryParams implements Cloneable {
}
public static enum BlockChangeType {
ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS, ENTITIES, ENTITIES_CREATED, ENTITIES_KILLED,
ALL,
BOTH,
CHESTACCESS,
CREATED,
DESTROYED,
CHAT,
KILLS,
ENTITIES,
ENTITIES_CREATED,
ENTITIES_KILLED,
}
public static enum Order {
ASC, DESC
ASC,
DESC
}
public static enum SummarizationMode {
NONE, PLAYERS, TYPES
NONE,
PLAYERS,
TYPES
}
}

View File

@ -1,49 +1,49 @@
package de.diddiz.LogBlock;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import static de.diddiz.LogBlock.config.Config.toolsByType;
import static org.bukkit.Bukkit.getServer;
public class Session {
private static final Map<String, Session> sessions = new HashMap<String, Session>();
public QueryParams lastQuery = null;
public LookupCacheElement[] lookupCache = null;
public int page = 1;
public Map<Tool, ToolData> toolData;
private Session(Player player) {
toolData = new HashMap<Tool, ToolData>();
final LogBlock logblock = LogBlock.getInstance();
if (player != null) {
for (final Tool tool : toolsByType.values()) {
toolData.put(tool, new ToolData(tool, logblock, player));
}
}
}
public static boolean hasSession(CommandSender sender) {
return sessions.containsKey(sender.getName().toLowerCase());
}
public static boolean hasSession(String playerName) {
return sessions.containsKey(playerName.toLowerCase());
}
public static Session getSession(CommandSender sender) {
return getSession(sender.getName());
}
public static Session getSession(String playerName) {
Session session = sessions.get(playerName.toLowerCase());
if (session == null) {
session = new Session(getServer().getPlayer(playerName));
sessions.put(playerName.toLowerCase(), session);
}
return session;
}
}
package de.diddiz.LogBlock;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import static de.diddiz.LogBlock.config.Config.toolsByType;
import static org.bukkit.Bukkit.getServer;
public class Session {
private static final Map<String, Session> sessions = new HashMap<>();
public QueryParams lastQuery = null;
public LookupCacheElement[] lookupCache = null;
public int page = 1;
public Map<Tool, ToolData> toolData;
private Session(Player player) {
toolData = new HashMap<>();
final LogBlock logblock = LogBlock.getInstance();
if (player != null) {
for (final Tool tool : toolsByType.values()) {
toolData.put(tool, new ToolData(tool, logblock, player));
}
}
}
public static boolean hasSession(CommandSender sender) {
return sessions.containsKey(sender.getName().toLowerCase());
}
public static boolean hasSession(String playerName) {
return sessions.containsKey(playerName.toLowerCase());
}
public static Session getSession(CommandSender sender) {
return getSession(sender.getName());
}
public static Session getSession(String playerName) {
Session session = sessions.get(playerName.toLowerCase());
if (session == null) {
session = new Session(getServer().getPlayer(playerName));
sessions.put(playerName.toLowerCase(), session);
}
return session;
}
}

View File

@ -1,36 +1,43 @@
package de.diddiz.LogBlock;
import de.diddiz.LogBlock.QueryParams.SummarizationMode;
import org.bukkit.Location;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;
import static de.diddiz.util.Utils.spaces;
public class SummedBlockChanges implements LookupCacheElement {
private final int type;
private final int created, destroyed;
private final float spaceFactor;
private final Actor actor;
public SummedBlockChanges(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException {
// Actor currently useless here as we don't yet output UUID in results anywhere
actor = p.sum == SummarizationMode.PLAYERS ? new Actor(rs) : null;
type = p.sum == SummarizationMode.TYPES ? rs.getInt("type") : 0;
created = rs.getInt("created");
destroyed = rs.getInt("destroyed");
this.spaceFactor = spaceFactor;
}
@Override
public Location getLocation() {
return null;
}
@Override
public String getMessage() {
return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : Objects.toString(MaterialConverter.getMaterial(type)));
}
}
package de.diddiz.LogBlock;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial;
import de.diddiz.LogBlock.QueryParams.SummarizationMode;
import de.diddiz.LogBlock.util.MessagingUtil;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Location;
public class SummedBlockChanges implements LookupCacheElement {
private final int type;
private final int created, destroyed;
private final float spaceFactor;
private final Actor actor;
public SummedBlockChanges(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException {
// Actor currently useless here as we don't yet output UUID in results anywhere
actor = p.sum == SummarizationMode.PLAYERS ? new Actor(rs) : null;
type = p.sum == SummarizationMode.TYPES ? rs.getInt("type") : 0;
created = rs.getInt("created");
destroyed = rs.getInt("destroyed");
this.spaceFactor = spaceFactor;
}
@Override
public Location getLocation() {
return null;
}
@Override
public BaseComponent[] getLogMessage(int entry) {
return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(MaterialConverter.getMaterial(type))), 10, 10, spaceFactor);
}
@Override
public int getNumChanges() {
return created + destroyed;
}
}

View File

@ -1,13 +1,16 @@
package de.diddiz.LogBlock;
import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial;
import de.diddiz.LogBlock.QueryParams.SummarizationMode;
import de.diddiz.LogBlock.util.MessagingUtil;
import org.bukkit.Location;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;
import static de.diddiz.util.Utils.spaces;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
public class SummedEntityChanges implements LookupCacheElement {
private final int type;
@ -30,7 +33,12 @@ public class SummedEntityChanges implements LookupCacheElement {
}
@Override
public String getMessage() {
return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : Objects.toString(EntityTypeConverter.getEntityType(type)));
public BaseComponent[] getLogMessage(int entry) {
return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(EntityTypeConverter.getEntityType(type))), 10, 10, spaceFactor);
}
@Override
public int getNumChanges() {
return created + destroyed;
}
}

View File

@ -1,11 +1,11 @@
package de.diddiz.LogBlock;
import org.bukkit.Location;
import de.diddiz.LogBlock.util.MessagingUtil;
import java.sql.ResultSet;
import java.sql.SQLException;
import static de.diddiz.util.Utils.spaces;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Location;
public class SummedKills implements LookupCacheElement {
private final Actor player;
@ -25,7 +25,12 @@ public class SummedKills implements LookupCacheElement {
}
@Override
public String getMessage() {
return kills + spaces((int) ((6 - String.valueOf(kills).length()) / spaceFactor)) + killed + spaces((int) ((7 - String.valueOf(killed).length()) / spaceFactor)) + player.getName();
public BaseComponent[] getLogMessage(int entry) {
return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor);
}
@Override
public int getNumChanges() {
return kills + killed;
}
}

View File

@ -1,35 +1,35 @@
package de.diddiz.LogBlock;
import org.bukkit.Material;
import org.bukkit.permissions.PermissionDefault;
import java.util.List;
public class Tool {
public final String name;
public final List<String> aliases;
public final ToolBehavior leftClickBehavior, rightClickBehavior;
public final boolean defaultEnabled;
public final Material item;
public final boolean canDrop;
public final QueryParams params;
public final ToolMode mode;
public final PermissionDefault permissionDefault;
public final boolean removeOnDisable;
public final boolean dropToDisable;
public Tool(String name, List<String> aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault, boolean removeOnDisable, boolean dropToDisable) {
this.name = name;
this.aliases = aliases;
this.leftClickBehavior = leftClickBehavior;
this.rightClickBehavior = rightClickBehavior;
this.defaultEnabled = defaultEnabled;
this.item = item;
this.canDrop = canDrop;
this.params = params;
this.mode = mode;
this.permissionDefault = permissionDefault;
this.removeOnDisable = removeOnDisable;
this.dropToDisable = dropToDisable;
}
}
package de.diddiz.LogBlock;
import org.bukkit.Material;
import org.bukkit.permissions.PermissionDefault;
import java.util.List;
public class Tool {
public final String name;
public final List<String> aliases;
public final ToolBehavior leftClickBehavior, rightClickBehavior;
public final boolean defaultEnabled;
public final Material item;
public final boolean canDrop;
public final QueryParams params;
public final ToolMode mode;
public final PermissionDefault permissionDefault;
public final boolean removeOnDisable;
public final boolean dropToDisable;
public Tool(String name, List<String> aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault, boolean removeOnDisable, boolean dropToDisable) {
this.name = name;
this.aliases = aliases;
this.leftClickBehavior = leftClickBehavior;
this.rightClickBehavior = rightClickBehavior;
this.defaultEnabled = defaultEnabled;
this.item = item;
this.canDrop = canDrop;
this.params = params;
this.mode = mode;
this.permissionDefault = permissionDefault;
this.removeOnDisable = removeOnDisable;
this.dropToDisable = dropToDisable;
}
}

View File

@ -1,5 +1,7 @@
package de.diddiz.LogBlock;
public enum ToolBehavior {
TOOL, BLOCK, NONE
}
package de.diddiz.LogBlock;
public enum ToolBehavior {
TOOL,
BLOCK,
NONE
}

View File

@ -1,15 +1,15 @@
package de.diddiz.LogBlock;
import org.bukkit.entity.Player;
public class ToolData {
public boolean enabled;
public QueryParams params;
public ToolMode mode;
public ToolData(Tool tool, LogBlock logblock, Player player) {
enabled = tool.defaultEnabled && logblock.hasPermission(player, "logblock.tools." + tool.name);
params = tool.params.clone();
mode = tool.mode;
}
}
package de.diddiz.LogBlock;
import org.bukkit.entity.Player;
public class ToolData {
public boolean enabled;
public QueryParams params;
public ToolMode mode;
public ToolData(Tool tool, LogBlock logblock, Player player) {
enabled = tool.defaultEnabled && logblock.hasPermission(player, "logblock.tools." + tool.name);
params = tool.params.clone();
mode = tool.mode;
}
}

View File

@ -1,14 +1,18 @@
package de.diddiz.LogBlock;
public enum ToolMode {
CLEARLOG("logblock.clearlog"), LOOKUP("logblock.lookup"), REDO("logblock.rollback"), ROLLBACK("logblock.rollback"), WRITELOGFILE("logblock.rollback");
private final String permission;
private ToolMode(String permission) {
this.permission = permission;
}
public String getPermission() {
return permission;
}
}
package de.diddiz.LogBlock;
public enum ToolMode {
CLEARLOG("logblock.clearlog"),
LOOKUP("logblock.lookup"),
REDO("logblock.rollback"),
ROLLBACK("logblock.rollback"),
WRITELOGFILE("logblock.rollback");
private final String permission;
private ToolMode(String permission) {
this.permission = permission;
}
public String getPermission() {
return permission;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@ import org.bukkit.block.data.type.TechnicalPiston.Type;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Bee;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.inventory.EquipmentSlot;
@ -27,10 +28,9 @@ import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.QueryParams.Order;
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
import de.diddiz.util.BukkitUtils;
import de.diddiz.util.Utils;
import de.diddiz.worldedit.WorldEditHelper;
import de.diddiz.LogBlock.util.BukkitUtils;
import de.diddiz.LogBlock.util.Utils;
import de.diddiz.LogBlock.worldedit.WorldEditHelper;
import java.io.File;
import java.io.PrintWriter;
import java.sql.ResultSet;
@ -43,10 +43,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import static de.diddiz.LogBlock.config.Config.dontRollback;
import static de.diddiz.LogBlock.config.Config.replaceAnyway;
import static de.diddiz.util.BukkitUtils.*;
import static de.diddiz.LogBlock.util.BukkitUtils.*;
public class WorldEditor implements Runnable {
private final LogBlock logblock;
@ -91,7 +93,6 @@ public class WorldEditor implements Runnable {
return blacklistCollisions;
}
public void setSender(CommandSender sender) {
this.sender = sender;
}
@ -148,7 +149,7 @@ public class WorldEditor implements Runnable {
@Override
public synchronized void run() {
final List<WorldEditorException> errorList = new ArrayList<WorldEditorException>();
final List<WorldEditorException> errorList = new ArrayList<>();
int counter = 0;
float size = edits.size();
while (!edits.isEmpty() && counter < 100) {
@ -181,11 +182,15 @@ public class WorldEditor implements Runnable {
logblock.getServer().getScheduler().cancelTask(taskID);
if (errorList.size() > 0) {
try {
final File file = new File("plugins/LogBlock/error/WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log");
file.getParentFile().mkdirs();
final File errorDir = new File(logblock.getDataFolder(), "error");
errorDir.mkdirs();
final File file = new File(errorDir, "WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log");
final PrintWriter writer = new PrintWriter(file);
for (final LookupCacheElement err : errorList) {
writer.println(err.getMessage());
for (final WorldEditorException err : errorList) {
writer.println(BaseComponent.toPlainText(err.getLogMessage()));
err.printStackTrace(writer);
writer.println();
writer.println();
}
writer.close();
} catch (final Exception ex) {
@ -202,12 +207,14 @@ public class WorldEditor implements Runnable {
}
public static enum PerformResult {
SUCCESS, BLACKLISTED, NO_ACTION
SUCCESS,
BLACKLISTED,
NO_ACTION
}
public interface Edit {
PerformResult perform() throws WorldEditorException;
public long getTime();
}
@ -321,6 +328,12 @@ public class WorldEditor implements Runnable {
}
}
return PerformResult.NO_ACTION; // the entity is not there, or equip does not match
} else if (changeType == EntityChangeType.GET_STUNG) {
UUID uuid = getReplacedUUID(entityId, entityUUID);
Entity existing = BukkitUtils.loadEntityAround(loc.getChunk(), uuid);
if (existing != null && existing instanceof Bee) {
((Bee) existing).setHasStung(!rollback);
}
}
return PerformResult.NO_ACTION;
}
@ -336,6 +349,7 @@ public class WorldEditor implements Runnable {
return date;
}
@Override
public PerformResult perform() throws WorldEditorException {
BlockData replacedBlock = getBlockReplaced();
BlockData setBlock = getBlockSet();
@ -348,9 +362,6 @@ public class WorldEditor implements Runnable {
return PerformResult.BLACKLISTED;
}
final Block block = loc.getBlock();
if (!world.isChunkLoaded(block.getChunk())) {
world.loadChunk(block.getChunk());
}
if (BukkitUtils.isEmpty(replacedBlock.getMaterial()) && BukkitUtils.isEmpty(block.getType())) {
return PerformResult.NO_ACTION;
}
@ -372,7 +383,7 @@ public class WorldEditor implements Runnable {
return PerformResult.NO_ACTION;
}
}
if (!forceReplace && block.getType() != setBlock.getMaterial() && !block.isEmpty() && !replaceAnyway.contains(block.getType())) {
if (!forceReplace && !BukkitUtils.isSimilarForRollback(setBlock.getMaterial(), block.getType()) && !block.isEmpty() && !replaceAnyway.contains(block.getType())) {
return PerformResult.NO_ACTION;
}
if (state instanceof Container && replacedBlock.getMaterial() != block.getType()) {
@ -443,6 +454,7 @@ public class WorldEditor implements Runnable {
public static class EditComparator implements Comparator<Edit> {
private final int mult;
public EditComparator(QueryParams.Order order) {
mult = order == Order.DESC ? 1 : -1;
}
@ -472,5 +484,10 @@ public class WorldEditor implements Runnable {
public Location getLocation() {
return loc;
}
@Override
public BaseComponent[] getLogMessage(int entry) {
return TextComponent.fromLegacyText(getMessage());
}
}
}

View File

@ -6,7 +6,7 @@ import java.sql.SQLException;
import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.QueryParams.BlockChangeType;
import de.diddiz.util.Utils;
import de.diddiz.LogBlock.util.Utils;
public class WorldEditorEditFactory {
private final WorldEditor editor;
@ -21,7 +21,7 @@ public class WorldEditorEditFactory {
public void processRow(ResultSet rs) throws SQLException {
if (params.bct == BlockChangeType.ENTITIES) {
editor.queueEntityEdit(rs, params, rollback);
editor.queueEntityEdit(rs, params, rollback);
return;
}
ChestAccess chestaccess = null;

View File

@ -0,0 +1,80 @@
package de.diddiz.LogBlock.addons.worldguard;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.registry.FlagConflictException;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.events.BlockChangePreLogEvent;
import de.diddiz.LogBlock.events.EntityChangePreLogEvent;
import java.util.logging.Level;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class WorldGuardLoggingFlagsAddon {
private final StateFlag LOGBLOCK_LOG_BLOCKS = new StateFlag("logblock-log-blocks", true);
private final StateFlag LOGBLOCK_LOG_ENTITIES = new StateFlag("logblock-log-entities", true);
private LogBlock plugin;
private WorldGuardPlugin worldGuard;
public WorldGuardLoggingFlagsAddon(LogBlock plugin) {
this.plugin = plugin;
}
public void onPluginLoad() {
registerFlags();
}
public void onPluginEnable() {
worldGuard = (WorldGuardPlugin) plugin.getServer().getPluginManager().getPlugin("WorldGuard");
plugin.getServer().getPluginManager().registerEvents(new LoggingListener(), plugin);
}
private void registerFlags() {
try {
FlagRegistry registry = WorldGuard.getInstance().getFlagRegistry();
registry.register(LOGBLOCK_LOG_BLOCKS);
registry.register(LOGBLOCK_LOG_ENTITIES);
} catch (FlagConflictException e) {
plugin.getLogger().log(Level.SEVERE, "Could not initialize Flags", e);
}
}
private class LoggingListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onBlockChangePreLog(BlockChangePreLogEvent event) {
RegionAssociable regionAssociable = null;
Location location = event.getLocation();
Entity actorEntity = event.getOwnerActor().getEntity();
if (actorEntity instanceof Player) {
regionAssociable = worldGuard.wrapPlayer((Player) actorEntity);
}
ApplicableRegionSet set = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().getApplicableRegions(BukkitAdapter.adapt(location));
if (!set.testState(regionAssociable, LOGBLOCK_LOG_BLOCKS)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onEntityChangePreLog(EntityChangePreLogEvent event) {
RegionAssociable regionAssociable = null;
Location location = event.getLocation();
Entity actorEntity = event.getOwnerActor().getEntity();
if (actorEntity instanceof Player) {
regionAssociable = worldGuard.wrapPlayer((Player) actorEntity);
}
ApplicableRegionSet set = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().getApplicableRegions(BukkitAdapter.adapt(location));
if (!set.testState(regionAssociable, LOGBLOCK_LOG_ENTITIES)) {
event.setCancelled(true);
}
}
}
}

View File

@ -1,5 +1,6 @@
package de.diddiz.LogBlock.blockstate;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.configuration.file.YamlConfiguration;
@ -11,5 +12,5 @@ public interface BlockStateCodec {
void deserialize(BlockState state, YamlConfiguration conf);
String toString(YamlConfiguration conf);
BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState);
}

View File

@ -1,7 +1,7 @@
package de.diddiz.LogBlock.blockstate;
import java.util.List;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.block.Banner;
@ -64,7 +64,7 @@ public class BlockStateCodecBanner implements BlockStateCodec {
}
@Override
public String toString(YamlConfiguration conf) {
public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) {
return null;
}
}

View File

@ -0,0 +1,54 @@
package de.diddiz.LogBlock.blockstate;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.Lectern;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
public class BlockStateCodecLectern implements BlockStateCodec {
@Override
public Material[] getApplicableMaterials() {
return new Material[] { Material.LECTERN };
}
@Override
public YamlConfiguration serialize(BlockState state) {
if (state instanceof Lectern) {
Lectern lectern = (Lectern) state;
ItemStack book = lectern.getSnapshotInventory().getItem(0);
if (book != null && book.getType() != Material.AIR) {
YamlConfiguration conf = new YamlConfiguration();
conf.set("book", book);
return conf;
}
}
return null;
}
@Override
public void deserialize(BlockState state, YamlConfiguration conf) {
if (state instanceof Lectern) {
Lectern lectern = (Lectern) state;
ItemStack book = null;
if (conf != null) {
book = conf.getItemStack("book");
}
try {
lectern.getSnapshotInventory().setItem(0, book);
} catch (NullPointerException e) {
//ignored
}
}
}
@Override
public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) {
if (conf != null) {
return new TextComponent("[book]");
}
return new TextComponent("empty");
}
}

View File

@ -0,0 +1,87 @@
package de.diddiz.LogBlock.blockstate;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.LogBlock.util.BukkitUtils;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.ShulkerBox;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
public class BlockStateCodecShulkerBox implements BlockStateCodec {
@Override
public Material[] getApplicableMaterials() {
return BukkitUtils.getShulkerBoxBlocks().toArray(Material[]::new);
}
@Override
public YamlConfiguration serialize(BlockState state) {
WorldConfig wcfg = getWorldConfig(state.getWorld());
if (wcfg == null || !wcfg.isLogging(Logging.SHULKER_BOX_CONTENT)) {
return null;
}
if (state instanceof ShulkerBox) {
ShulkerBox shulkerBox = (ShulkerBox) state;
ItemStack[] content = shulkerBox.getSnapshotInventory().getStorageContents();
YamlConfiguration conf = new YamlConfiguration();
boolean anySlot = false;
for (int i = 0; i < content.length; i++) {
ItemStack stack = content[i];
if (stack != null && stack.getType() != Material.AIR) {
conf.set("slot" + i, stack);
anySlot = true;
}
}
if (anySlot) {
return conf;
}
}
return null;
}
@Override
public void deserialize(BlockState state, YamlConfiguration conf) {
if (state instanceof ShulkerBox) {
ShulkerBox shulkerBox = (ShulkerBox) state;
if (conf != null) {
ItemStack[] content = shulkerBox.getSnapshotInventory().getStorageContents();
for (int i = 0; i < content.length; i++) {
ItemStack stack = conf.getItemStack("slot" + i);
if (stack != null && stack.getType() != Material.AIR) {
content[i] = stack;
}
}
shulkerBox.getSnapshotInventory().setContents(content);
}
}
}
@Override
public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) {
if (conf != null) {
StringBuilder sb = new StringBuilder();
sb.append("[");
boolean anySlot = false;
for (String key : conf.getKeys(false)) {
if (key.startsWith("slot")) {
ItemStack stack = conf.getItemStack(key);
if (stack != null && stack.getType() != Material.AIR) {
if (anySlot) {
sb.append(",");
}
anySlot = true;
sb.append(stack.getAmount()).append("x").append(stack.getType());
}
}
}
sb.append("]");
return anySlot ? new TextComponent(sb.toString()) : null;
}
return null;
}
}

View File

@ -1,47 +1,88 @@
package de.diddiz.LogBlock.blockstate;
import de.diddiz.LogBlock.util.BukkitUtils;
import java.awt.Color;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
public class BlockStateCodecSign implements BlockStateCodec {
@Override
public Material[] getApplicableMaterials() {
return new Material[] { Material.WALL_SIGN, Material.SIGN };
return BukkitUtils.getAllSignMaterials().toArray(Material[]::new);
}
@Override
public YamlConfiguration serialize(BlockState state) {
if (state instanceof Sign) {
Sign sign = (Sign) state;
String[] lines = sign.getLines();
boolean hasText = false;
for (int i = 0; i < lines.length; i++) {
if (lines[i] != null && lines[i].length() > 0) {
hasText = true;
break;
YamlConfiguration conf = null;
if (state instanceof Sign sign) {
boolean waxed = sign.isWaxed();
if (waxed) {
conf = new YamlConfiguration();
conf.set("waxed", waxed);
}
for (Side side : Side.values()) {
SignSide signSide = sign.getSide(side);
String[] lines = signSide.getLines();
boolean hasText = false;
for (int i = 0; i < lines.length; i++) {
if (lines[i] != null && lines[i].length() > 0) {
hasText = true;
break;
}
}
DyeColor signColor = signSide.getColor();
if (signColor == null) {
signColor = DyeColor.BLACK;
}
boolean glowing = signSide.isGlowingText();
if (hasText || signColor != DyeColor.BLACK || glowing) {
if (conf == null) {
conf = new YamlConfiguration();
}
ConfigurationSection sideSection = side == Side.FRONT ? conf : conf.createSection(side.name().toLowerCase());
if (hasText) {
sideSection.set("lines", Arrays.asList(lines));
}
if (signColor != DyeColor.BLACK) {
sideSection.set("color", signColor.name());
}
if (glowing) {
sideSection.set("glowing", true);
}
}
}
if (hasText) {
YamlConfiguration conf = new YamlConfiguration();
conf.set("lines", Arrays.asList(lines));
return conf;
}
}
return null;
return conf;
}
/**
* This is required for the SignChangeEvent, because we have no BlockState there.
* This is required for the SignChangeEvent, because we have no updated BlockState there.
* @param state
*/
public static YamlConfiguration serialize(String[] lines) {
YamlConfiguration conf = new YamlConfiguration();
conf.set("lines", Arrays.asList(lines));
public YamlConfiguration serialize(BlockState state, Side side, String[] lines) {
YamlConfiguration conf = state == null ? null : serialize(state);
if (lines != null) {
if (conf == null) {
conf = new YamlConfiguration();
}
ConfigurationSection sideSection = side == Side.FRONT ? conf : conf.getConfigurationSection(side.name().toLowerCase());
if (sideSection == null) {
sideSection = conf.createSection(side.name().toLowerCase());
}
sideSection.set("lines", Arrays.asList(lines));
}
return conf;
}
@ -49,28 +90,138 @@ public class BlockStateCodecSign implements BlockStateCodec {
public void deserialize(BlockState state, YamlConfiguration conf) {
if (state instanceof Sign) {
Sign sign = (Sign) state;
List<String> lines = Collections.emptyList();
if (conf != null) {
lines = conf.getStringList("lines");
}
for (int i = 0; i < 4; i++) {
String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : "";
sign.setLine(i, line);
sign.setWaxed(conf.getBoolean("waxed"));
for (Side side : Side.values()) {
ConfigurationSection sideSection = side == Side.FRONT ? conf : conf.getConfigurationSection(side.name().toLowerCase());
DyeColor signColor = DyeColor.BLACK;
boolean glowing = false;
List<String> lines = Collections.emptyList();
if (sideSection != null) {
if (sideSection.contains("lines")) {
lines = sideSection.getStringList("lines");
}
if (sideSection.contains("color")) {
try {
signColor = DyeColor.valueOf(sideSection.getString("color"));
} catch (IllegalArgumentException | NullPointerException e) {
// ignored
}
}
glowing = sideSection.getBoolean("glowing", false);
}
SignSide signSide = sign.getSide(side);
for (int i = 0; i < 4; i++) {
String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : "";
signSide.setLine(i, line);
}
signSide.setColor(signColor);
signSide.setGlowingText(glowing);
}
} else {
sign.setWaxed(false);
for (Side side : Side.values()) {
SignSide signSide = sign.getSide(side);
for (int i = 0; i < 4; i++) {
signSide.setLine(i, "");
}
signSide.setColor(DyeColor.BLACK);
signSide.setGlowingText(false);
}
}
}
}
@Override
public String toString(YamlConfiguration conf) {
if (conf != null) {
StringBuilder sb = new StringBuilder();
for (String line : conf.getStringList("lines")) {
if (sb.length() > 0)
sb.append(" ");
sb.append("[").append(line).append("]");
public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfiguration oldState) {
if (state != null) {
TextComponent tc = new TextComponent();
// StringBuilder sb = new StringBuilder();
boolean isWaxed = state.getBoolean("waxed");
boolean oldWaxed = oldState != null && oldState.getBoolean("waxed");
if (isWaxed != oldWaxed) {
tc.addExtra(isWaxed ? "(waxed)" : "(not waxed)");
}
return sb.toString();
for (Side side : Side.values()) {
boolean sideHeaderAdded = false;
ConfigurationSection sideSection = side == Side.FRONT ? state : state.getConfigurationSection(side.name().toLowerCase());
List<String> lines = sideSection == null ? Collections.emptyList() : sideSection.getStringList("lines");
List<String> oldLines = Collections.emptyList();
DyeColor signColor = DyeColor.BLACK;
if (sideSection != null && sideSection.contains("color")) {
try {
signColor = DyeColor.valueOf(sideSection.getString("color"));
} catch (IllegalArgumentException | NullPointerException e) {
// ignored
}
}
DyeColor oldSignColor = DyeColor.BLACK;
boolean glowing = sideSection != null && sideSection.getBoolean("glowing", false);
boolean oldGlowing = false;
if (oldState != null) {
ConfigurationSection oldSideSection = side == Side.FRONT ? oldState : oldState.getConfigurationSection(side.name().toLowerCase());
if (oldSideSection != null) {
oldLines = oldSideSection.getStringList("lines");
if (oldSideSection.contains("color")) {
try {
oldSignColor = DyeColor.valueOf(oldSideSection.getString("color"));
} catch (IllegalArgumentException | NullPointerException e) {
// ignored
}
}
oldGlowing = oldSideSection.getBoolean("glowing", false);
}
}
if (!lines.equals(oldLines)) {
sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded);
for (String line : lines) {
if (tc.getExtra() != null && !tc.getExtra().isEmpty()) {
tc.addExtra(" ");
}
tc.addExtra("[");
if (line != null && !line.isEmpty()) {
tc.addExtra(new TextComponent(TextComponent.fromLegacyText(line)));
}
tc.addExtra("]");
}
}
if (signColor != oldSignColor) {
sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded);
if (tc.getExtra() != null && !tc.getExtra().isEmpty()) {
tc.addExtra(" ");
}
tc.addExtra("(color: ");
TextComponent colorText = new TextComponent(signColor.name().toLowerCase());
colorText.setColor(ChatColor.of(new Color(signColor.getColor().asARGB())));
tc.addExtra(colorText);
tc.addExtra(")");
}
if (glowing != oldGlowing) {
sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded);
if (tc.getExtra() != null && !tc.getExtra().isEmpty()) {
tc.addExtra(" ");
}
if (glowing) {
tc.addExtra("(glowing)");
} else {
tc.addExtra("(not glowing)");
}
}
}
return tc;
}
return null;
}
private static boolean addSideHeaderText(TextComponent tc, Side side, boolean wasAdded) {
if (!wasAdded) {
if (tc.getExtra() != null && !tc.getExtra().isEmpty()) {
tc.addExtra(" ");
}
tc.addExtra(side.name() + ":");
}
return true;
}
}

View File

@ -1,15 +1,30 @@
package de.diddiz.LogBlock.blockstate;
import java.util.UUID;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Text;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.profile.PlayerProfile;
public class BlockStateCodecSkull implements BlockStateCodec {
private static final boolean HAS_PROFILE_API;
static {
boolean hasProfileApi = false;
try {
Skull.class.getMethod("getOwnerProfile");
hasProfileApi = true;
} catch (NoSuchMethodException ignored) {
}
HAS_PROFILE_API = hasProfileApi;
}
@Override
public Material[] getApplicableMaterials() {
return new Material[] { Material.PLAYER_WALL_HEAD, Material.PLAYER_HEAD };
@ -20,9 +35,14 @@ public class BlockStateCodecSkull implements BlockStateCodec {
if (state instanceof Skull) {
Skull skull = (Skull) state;
OfflinePlayer owner = skull.hasOwner() ? skull.getOwningPlayer() : null;
if (owner != null) {
PlayerProfile profile = HAS_PROFILE_API ? skull.getOwnerProfile() : null;
if (owner != null || profile != null) {
YamlConfiguration conf = new YamlConfiguration();
conf.set("owner", owner.getUniqueId().toString());
if (profile != null) {
conf.set("profile", profile);
} else if (owner != null) {
conf.set("owner", owner.getUniqueId().toString());
}
return conf;
}
}
@ -33,21 +53,37 @@ public class BlockStateCodecSkull implements BlockStateCodec {
public void deserialize(BlockState state, YamlConfiguration conf) {
if (state instanceof Skull) {
Skull skull = (Skull) state;
UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner"));
if (ownerId == null) {
skull.setOwningPlayer(null);
PlayerProfile profile = conf == null || !HAS_PROFILE_API ? null : (PlayerProfile) conf.get("profile");
if (profile != null) {
skull.setOwnerProfile(profile);
} else {
skull.setOwningPlayer(Bukkit.getOfflinePlayer(ownerId));
UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner"));
if (ownerId == null) {
skull.setOwningPlayer(null);
} else {
skull.setOwningPlayer(Bukkit.getOfflinePlayer(ownerId));
}
}
}
}
@Override
public String toString(YamlConfiguration conf) {
UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner"));
public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) {
if (HAS_PROFILE_API && conf != null) {
PlayerProfile profile = (PlayerProfile) conf.get("profile");
if (profile != null) {
TextComponent tc = new TextComponent("[" + (profile.getName() != null ? profile.getName() : (profile.getUniqueId() != null ? profile.getUniqueId().toString() : "~unknown~")) + "]");
if (profile.getName() != null && profile.getUniqueId() != null) {
tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("UUID: " + profile.getUniqueId().toString())));
}
return tc;
}
}
String ownerIdString = conf == null ? null : conf.getString("owner");
UUID ownerId = ownerIdString == null ? null : UUID.fromString(ownerIdString);
if (ownerId != null) {
OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerId);
return "[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]";
return new TextComponent("[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]");
}
return null;
}

View File

@ -1,5 +1,8 @@
package de.diddiz.LogBlock.blockstate;
import de.diddiz.LogBlock.LogBlock;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
@ -23,7 +26,9 @@ public class BlockStateCodecSpawner implements BlockStateCodec {
conf.set("minSpawnDelay", spawner.getMinSpawnDelay());
conf.set("requiredPlayerRange", spawner.getRequiredPlayerRange());
conf.set("spawnCount", spawner.getSpawnCount());
conf.set("spawnedType", spawner.getSpawnedType().name());
if (spawner.getSpawnedType() != null) {
conf.set("spawnedType", spawner.getSpawnedType().name());
}
conf.set("spawnRange", spawner.getSpawnRange());
return conf;
}
@ -41,18 +46,27 @@ public class BlockStateCodecSpawner implements BlockStateCodec {
spawner.setMinSpawnDelay(conf.getInt("minSpawnDelay"));
spawner.setRequiredPlayerRange(conf.getInt("requiredPlayerRange"));
spawner.setSpawnCount(conf.getInt("spawnCount"));
spawner.setSpawnedType(EntityType.valueOf(conf.getString("spawnedType")));
EntityType spawnedType = null;
String spawnedTypeString = conf.getString("spawnedType");
if (spawnedTypeString != null) {
try {
spawnedType = EntityType.valueOf(spawnedTypeString);
} catch (IllegalArgumentException ignored) {
LogBlock.getInstance().getLogger().warning("Could not find spawner spawned type: " + spawnedTypeString);
}
}
spawner.setSpawnedType(spawnedType);
spawner.setSpawnRange(conf.getInt("spawnRange"));
}
}
}
@Override
public String toString(YamlConfiguration conf) {
public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) {
if (conf != null) {
EntityType entity = EntityType.valueOf(conf.getString("spawnedType"));
if (entity != null) {
return "[" + entity + "]";
return new TextComponent("[" + entity.getKey().getKey() + "]");
}
}
return null;

View File

@ -1,14 +1,14 @@
package de.diddiz.LogBlock.blockstate;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.configuration.file.YamlConfiguration;
public class BlockStateCodecs {
private static Map<Material, BlockStateCodec> codecs = new EnumMap<>(Material.class);
private static Map<Material, BlockStateCodec> codecs = new HashMap<>();
public static void registerCodec(BlockStateCodec codec) {
Material[] materials = codec.getApplicableMaterials();
@ -25,6 +25,8 @@ public class BlockStateCodecs {
registerCodec(new BlockStateCodecSkull());
registerCodec(new BlockStateCodecBanner());
registerCodec(new BlockStateCodecSpawner());
registerCodec(new BlockStateCodecLectern());
registerCodec(new BlockStateCodecShulkerBox());
}
public static boolean hasCodec(Material material) {
@ -49,10 +51,10 @@ public class BlockStateCodecs {
}
}
public static String toString(Material material, YamlConfiguration state) {
public static BaseComponent getChangesAsComponent(Material material, YamlConfiguration state, YamlConfiguration oldState) {
BlockStateCodec codec = codecs.get(material);
if (codec != null) {
return codec.toString(state);
return codec.getChangesAsComponent(state, oldState);
}
return null;
}

View File

@ -1,8 +1,7 @@
package de.diddiz.LogBlock.config;
import de.diddiz.LogBlock.*;
import de.diddiz.util.ComparableVersion;
import de.diddiz.LogBlock.util.ComparableVersion;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
@ -17,17 +16,18 @@ import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.zip.DataFormatException;
import static de.diddiz.util.BukkitUtils.friendlyWorldname;
import static de.diddiz.util.Utils.parseTimeSpec;
import static de.diddiz.LogBlock.util.BukkitUtils.friendlyWorldname;
import static de.diddiz.LogBlock.util.Utils.parseTimeSpec;
import static org.bukkit.Bukkit.*;
public class Config {
private static LoggingEnabledMapping superWorldConfig;
private static Map<String, WorldConfig> worldConfigs;
public static String url, user, password;
public static String mysqlDatabase;
public static boolean mysqlUseSSL;
public static boolean mysqlRequireSSL;
public static int delayBetweenRuns, forceToProcessAtLeast, timePerRun;
public static boolean fireCustomEvents;
public static boolean useBukkitScheduler;
public static int queueWarningSize;
public static boolean enableAutoClearLog;
@ -51,21 +51,27 @@ public class Config {
public static Set<String> hiddenPlayers;
public static List<String> ignoredChat;
public static SimpleDateFormat formatter;
public static boolean safetyIdCheck;
public static SimpleDateFormat formatterShort;
public static boolean debug;
public static boolean logEnvironmentalKills;
// addons
public static boolean worldGuardLoggingFlags;
// Not loaded from config - checked at runtime
public static boolean mb4 = false;
public static final String CURRENT_CONFIG_VERSION = "1.19.0";
public static enum LogKillsLevel {
PLAYERS, MONSTERS, ANIMALS;
PLAYERS,
MONSTERS,
ANIMALS;
}
public static void load(LogBlock logblock) throws DataFormatException, IOException {
final ConfigurationSection config = logblock.getConfig();
final Map<String, Object> def = new HashMap<String, Object>();
def.put("version", logblock.getDescription().getVersion());
final List<String> worldNames = new ArrayList<String>();
final Map<String, Object> def = new HashMap<>();
def.put("version", CURRENT_CONFIG_VERSION);
final List<String> worldNames = new ArrayList<>();
for (final World world : getWorlds()) {
worldNames.add(world.getName());
}
@ -75,21 +81,22 @@ public class Config {
worldNames.add("world_the_end");
}
def.put("loggedWorlds", worldNames);
def.put("mysql.protocol", "mysql");
def.put("mysql.host", "localhost");
def.put("mysql.port", 3306);
def.put("mysql.database", "minecraft");
def.put("mysql.user", "username");
def.put("mysql.password", "pass");
def.put("mysql.useSSL", true);
def.put("mysql.requireSSL", false);
def.put("consumer.delayBetweenRuns", 2);
def.put("consumer.forceToProcessAtLeast", 200);
def.put("consumer.timePerRun", 1000);
def.put("consumer.fireCustomEvents", false);
def.put("consumer.useBukkitScheduler", true);
def.put("consumer.queueWarningSize", 1000);
def.put("clearlog.dumpDeletedLog", false);
def.put("clearlog.enableAutoClearLog", false);
final List<String> autoClearlog = new ArrayList<String>();
final List<String> autoClearlog = new ArrayList<>();
for (final String world : worldNames) {
autoClearlog.add("world \"" + world + "\" before 365 days all");
autoClearlog.add("world \"" + world + "\" player lavaflow waterflow leavesdecay before 7 days all");
@ -117,11 +124,17 @@ public class Config {
def.put("lookup.linesLimit", 1500);
def.put("lookup.hardLinesLimit", 100000);
try {
formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "MM-dd HH:mm:ss"));
formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "yyyy-MM-dd HH:mm:ss"));
} catch (IllegalArgumentException e) {
throw new DataFormatException("Invalid specification for date format, please see http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html : " + e.getMessage());
}
def.put("lookup.dateFormat", "MM-dd HH:mm:ss");
def.put("lookup.dateFormat", "yyyy-MM-dd HH:mm:ss");
try {
formatterShort = new SimpleDateFormat(config.getString("lookup.dateFormatShort", "MM-dd HH:mm"));
} catch (IllegalArgumentException e) {
throw new DataFormatException("Invalid specification for date format, please see http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html : " + e.getMessage());
}
def.put("lookup.dateFormatShort", "MM-dd HH:mm");
def.put("questioner.askRollbacks", true);
def.put("questioner.askRedos", true);
def.put("questioner.askClearLogs", true);
@ -151,25 +164,30 @@ public class Config {
def.put("tools.toolblock.mode", "LOOKUP");
def.put("tools.toolblock.permissionDefault", "OP");
def.put("safety.id.check", true);
def.put("addons.worldguardLoggingFlags", false);
def.put("debug", false);
for (final Entry<String, Object> e : def.entrySet()) {
if (!config.contains(e.getKey())) {
config.set(e.getKey(), e.getValue());
}
}
if (config.contains("consumer.fireCustomEvents")) {
config.set("consumer.fireCustomEvents", null);
}
logblock.saveConfig();
ComparableVersion configVersion = new ComparableVersion(config.getString("version"));
boolean oldConfig = configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) < 0;
url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database");
boolean oldConfig = configVersion.compareTo(new ComparableVersion(CURRENT_CONFIG_VERSION)) < 0;
mysqlDatabase = getStringIncludingInts(config, "mysql.database");
url = "jdbc:" + config.getString("mysql.protocol") + "://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + mysqlDatabase;
user = getStringIncludingInts(config, "mysql.user");
password = getStringIncludingInts(config, "mysql.password");
mysqlUseSSL = config.getBoolean("mysql.useSSL", true);
mysqlRequireSSL = config.getBoolean("mysql.requireSSL", false);
delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2);
forceToProcessAtLeast = config.getInt("consumer.forceToProcessAtLeast", 0);
timePerRun = config.getInt("consumer.timePerRun", 1000);
fireCustomEvents = config.getBoolean("consumer.fireCustomEvents", false);
useBukkitScheduler = config.getBoolean("consumer.useBukkitScheduler", true);
queueWarningSize = config.getInt("consumer.queueWarningSize", 1000);
enableAutoClearLog = config.getBoolean("clearlog.enableAutoClearLog");
@ -187,11 +205,11 @@ public class Config {
throw new DataFormatException("logging.logKillsLevel doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'");
}
logEnvironmentalKills = config.getBoolean("logging.logEnvironmentalKills", false);
hiddenPlayers = new HashSet<String>();
hiddenPlayers = new HashSet<>();
for (final String playerName : config.getStringList("logging.hiddenPlayers")) {
hiddenPlayers.add(playerName.toLowerCase().trim());
}
hiddenBlocks = new HashSet<Material>();
hiddenBlocks = new HashSet<>();
for (final String blocktype : config.getStringList("logging.hiddenBlocks")) {
final Material mat = Material.matchMaterial(blocktype);
if (mat != null) {
@ -200,11 +218,11 @@ public class Config {
throw new DataFormatException("Not a valid material in hiddenBlocks: '" + blocktype + "'");
}
}
ignoredChat = new ArrayList<String>();
ignoredChat = new ArrayList<>();
for (String chatCommand : config.getStringList("logging.ignoredChat")) {
ignoredChat.add(chatCommand.toLowerCase());
}
dontRollback = new HashSet<Material>();
dontRollback = new HashSet<>();
for (String e : config.getStringList("rollback.dontRollback")) {
Material mat = Material.matchMaterial(e);
if (mat != null) {
@ -213,7 +231,7 @@ public class Config {
throw new DataFormatException("Not a valid material in dontRollback: '" + e + "'");
}
}
replaceAnyway = new HashSet<Material>();
replaceAnyway = new HashSet<>();
for (String e : config.getStringList("rollback.replaceAnyway")) {
Material mat = Material.matchMaterial(e);
if (mat != null) {
@ -234,10 +252,9 @@ public class Config {
askClearLogs = config.getBoolean("questioner.askClearLogs", true);
askClearLogAfterRollback = config.getBoolean("questioner.askClearLogAfterRollback", true);
askRollbackAfterBan = config.getBoolean("questioner.askRollbackAfterBan", false);
safetyIdCheck = config.getBoolean("safety.id.check", true);
debug = config.getBoolean("debug", false);
banPermission = config.getString("questioner.banPermission");
final List<Tool> tools = new ArrayList<Tool>();
final List<Tool> tools = new ArrayList<>();
final ConfigurationSection toolsSec = config.getConfigurationSection("tools");
for (final String toolName : toolsSec.getKeys(false)) {
try {
@ -246,7 +263,7 @@ public class Config {
final ToolBehavior leftClickBehavior = ToolBehavior.valueOf(tSec.getString("leftClickBehavior").toUpperCase());
final ToolBehavior rightClickBehavior = ToolBehavior.valueOf(tSec.getString("rightClickBehavior").toUpperCase());
final boolean defaultEnabled = tSec.getBoolean("defaultEnabled", false);
final Material item = Material.matchMaterial(tSec.getString("item","OAK_LOG"));
final Material item = Material.matchMaterial(tSec.getString("item", "OAK_LOG"));
final boolean canDrop = tSec.getBoolean("canDrop", false);
final boolean removeOnDisable = tSec.getBoolean("removeOnDisable", true);
final boolean dropToDisable = tSec.getBoolean("dropToDisable", false);
@ -260,8 +277,8 @@ public class Config {
getLogger().log(Level.WARNING, "Error at parsing tool '" + toolName + "': ", ex);
}
}
toolsByName = new HashMap<String, Tool>();
toolsByType = new HashMap<Material, Tool>();
toolsByName = new HashMap<>();
toolsByType = new HashMap<>();
for (final Tool tool : tools) {
toolsByType.put(tool.item, tool);
toolsByName.put(tool.name.toLowerCase(), tool);
@ -269,8 +286,9 @@ public class Config {
toolsByName.put(alias, tool);
}
}
worldGuardLoggingFlags = config.getBoolean("addons.worldguardLoggingFlags");
final List<String> loggedWorlds = config.getStringList("loggedWorlds");
worldConfigs = new HashMap<String, WorldConfig>();
worldConfigs = new HashMap<>();
if (loggedWorlds.isEmpty()) {
throw new DataFormatException("No worlds configured");
}
@ -341,6 +359,11 @@ public class Config {
}
return false;
}
public static boolean isLoggingNatualSpawns(World world) {
final WorldConfig wcfg = worldConfigs.get(world.getName());
return wcfg != null && wcfg.logNaturalEntitySpawns;
}
}
class LoggingEnabledMapping {

View File

@ -7,8 +7,8 @@ import java.util.List;
import org.bukkit.entity.EntityType;
public enum EntityLogging {
SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name() }),
DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name(), "ANIMAL" }),
SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.SNOWMAN.name() }),
DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.SNOWMAN.name(), "ANIMAL" }),
MODIFY(new String[] { "ALL" });
public static final int length = EntityLogging.values().length;

View File

@ -1,147 +1,171 @@
package de.diddiz.LogBlock.config;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.util.BukkitUtils;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Animals;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.entity.WaterMob;
import java.io.File;
import java.io.IOException;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
public class WorldConfig extends LoggingEnabledMapping {
public final String world;
public final String table;
public final String insertBlockStatementString;
public final String selectBlockActorIdStatementString;
public final String insertBlockStateStatementString;
public final String insertBlockChestDataStatementString;
public final String insertEntityStatementString;
public final String updateEntityUUIDString;
private final EnumMap<EntityLogging, EntityLoggingList> entityLogging = new EnumMap<>(EntityLogging.class);
public WorldConfig(String world, File file) throws IOException {
this.world = world;
final Map<String, Object> def = new HashMap<String, Object>();
// "Before MySQL 5.1.6, database and table names cannot contain "/", "\", ".", or characters that are not permitted in file names" - MySQL manual
// They _can_ contain spaces, but replace them as well
def.put("table", "lb-" + file.getName().substring(0, file.getName().length() - 4).replaceAll("[ ./\\\\]", "_"));
for (final Logging l : Logging.values()) {
def.put("logging." + l.toString(), l.isDefaultEnabled());
}
final YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
for (final Entry<String, Object> e : def.entrySet()) {
if (config.get(e.getKey()) == null) {
config.set(e.getKey(), e.getValue());
}
}
for (EntityLogging el : EntityLogging.values()) {
if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) {
config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled());
}
entityLogging.put(el, new EntityLoggingList(config.getStringList("entity." + el.name().toLowerCase())));
}
config.save(file);
table = config.getString("table");
for (final Logging l : Logging.values()) {
setLogging(l, config.getBoolean("logging." + l.toString()));
}
insertBlockStatementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)";
selectBlockActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1";
insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)";
insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)";
insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)";
updateEntityUUIDString = "UPDATE `" + table + "-entityids` SET entityuuid = ? WHERE entityid = ?";
}
public boolean isLogging(EntityLogging logging, Entity entity) {
return entityLogging.get(logging).isLogging(entity);
}
public boolean isLoggingAnyEntities() {
for (EntityLoggingList list : entityLogging.values()) {
if (list.isLoggingAnyEntities()) {
return true;
}
}
return false;
}
private class EntityLoggingList {
private final EnumSet<EntityType> logged = EnumSet.noneOf(EntityType.class);
private final boolean logAll;
private final boolean logAnimals;
private final boolean logMonsters;
private final boolean logLiving;
public EntityLoggingList(List<String> types) {
boolean all = false;
boolean animals = false;
boolean monsters = false;
boolean living = false;
for (String type : types) {
EntityType et = BukkitUtils.matchEntityType(type);
if (et != null) {
logged.add(et);
} else {
if (type.equalsIgnoreCase("all")) {
all = true;
} else if (type.equalsIgnoreCase("animal") || type.equalsIgnoreCase("animals")) {
animals = true;
} else if (type.equalsIgnoreCase("monster") || type.equalsIgnoreCase("monsters")) {
monsters = true;
} else if (type.equalsIgnoreCase("living")) {
living = true;
} else {
LogBlock.getInstance().getLogger().log(Level.WARNING, "Unkown entity type in config for " + world + ": " + type);
}
}
}
logAll = all;
logAnimals = animals;
logMonsters = monsters;
logLiving = living;
}
public boolean isLogging(Entity entity) {
if (entity == null || (entity instanceof Player)) {
return false;
}
EntityType type = entity.getType();
if (logAll || logged.contains(type)) {
return true;
}
if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) {
return true;
}
if (logAnimals && (Animals.class.isAssignableFrom(entity.getClass()) || WaterMob.class.isAssignableFrom(entity.getClass()))) {
return true;
}
if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) {
return true;
}
return false;
}
public boolean isLoggingAnyEntities() {
return logAll || logAnimals || logLiving || logMonsters || !logged.isEmpty();
}
}
}
package de.diddiz.LogBlock.config;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.util.BukkitUtils;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Animals;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.entity.WaterMob;
import java.io.File;
import java.io.IOException;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
public class WorldConfig extends LoggingEnabledMapping {
public final String world;
public final String table;
public final String insertBlockStatementString;
public final String selectBlockActorIdStatementString;
public final String insertBlockStateStatementString;
public final String insertBlockChestDataStatementString;
public final String insertEntityStatementString;
public final String updateEntityUUIDString;
private final EnumMap<EntityLogging, EntityLoggingList> entityLogging = new EnumMap<>(EntityLogging.class);
public final boolean logNaturalEntitySpawns;
public final boolean logAllNamedEntityKills;
public WorldConfig(String world, File file) throws IOException {
this.world = world;
final Map<String, Object> def = new HashMap<>();
// "Before MySQL 5.1.6, database and table names cannot contain "/", "\", ".", or characters that are not permitted in file names" - MySQL manual
// They _can_ contain spaces, but replace them as well
def.put("table", "lb-" + file.getName().substring(0, file.getName().length() - 4).replaceAll("[ ./\\\\]", "_"));
for (final Logging l : Logging.values()) {
def.put("logging." + l.toString(), l.isDefaultEnabled());
}
final YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
for (final Entry<String, Object> e : def.entrySet()) {
if (config.get(e.getKey()) == null) {
config.set(e.getKey(), e.getValue());
}
}
for (EntityLogging el : EntityLogging.values()) {
if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) {
config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled());
}
entityLogging.put(el, new EntityLoggingList(el, config.getStringList("entity." + el.name().toLowerCase())));
}
if (!config.isBoolean("entity.logNaturalSpawns")) {
config.set("entity.logNaturalSpawns", false);
}
logNaturalEntitySpawns = config.getBoolean("entity.logNaturalSpawns");
if (!config.isBoolean("entity.logAllNamedEntityKills")) {
config.set("entity.logAllNamedEntityKills", true);
}
logAllNamedEntityKills = config.getBoolean("entity.logAllNamedEntityKills");
config.save(file);
table = config.getString("table");
for (final Logging l : Logging.values()) {
setLogging(l, config.getBoolean("logging." + l.toString()));
}
insertBlockStatementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)";
selectBlockActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1";
insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)";
insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)";
insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)";
updateEntityUUIDString = "UPDATE `" + table + "-entityids` SET entityuuid = ? WHERE entityid = ?";
}
public boolean isLogging(EntityLogging logging, Entity entity) {
return entityLogging.get(logging).isLogging(entity);
}
public boolean isLoggingAnyEntities() {
for (EntityLoggingList list : entityLogging.values()) {
if (list.isLoggingAnyEntities()) {
return true;
}
}
return false;
}
private class EntityLoggingList {
private final EntityLogging entityAction;
private final HashSet<EntityType> logged = new HashSet<>();
private final boolean logAll;
private final boolean logAnimals;
private final boolean logWateranimals;
private final boolean logMonsters;
private final boolean logLiving;
public EntityLoggingList(EntityLogging entityAction, List<String> types) {
this.entityAction = entityAction;
boolean all = false;
boolean animals = false;
boolean wateranimals = false;
boolean monsters = false;
boolean living = false;
for (String type : types) {
EntityType et = BukkitUtils.matchEntityType(type);
if (et != null) {
logged.add(et);
} else {
if (type.equalsIgnoreCase("all")) {
all = true;
} else if (type.equalsIgnoreCase("animal") || type.equalsIgnoreCase("animals")) {
animals = true;
} else if (type.equalsIgnoreCase("wateranimal") || type.equalsIgnoreCase("wateranimals")) {
wateranimals = true;
} else if (type.equalsIgnoreCase("monster") || type.equalsIgnoreCase("monsters")) {
monsters = true;
} else if (type.equalsIgnoreCase("living")) {
living = true;
} else {
LogBlock.getInstance().getLogger().log(Level.WARNING, "Unkown entity type in config for " + world + ": " + type);
}
}
}
logAll = all;
logAnimals = animals;
logWateranimals = wateranimals;
logMonsters = monsters;
logLiving = living;
}
public boolean isLogging(Entity entity) {
if (entity == null || (entity instanceof Player)) {
return false;
}
EntityType type = entity.getType();
if (logAll || logged.contains(type)) {
return true;
}
if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) {
return true;
}
if (logAnimals && Animals.class.isAssignableFrom(entity.getClass())) {
return true;
}
if (logWateranimals && WaterMob.class.isAssignableFrom(entity.getClass())) {
return true;
}
if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) {
return true;
}
if (entityAction == EntityLogging.DESTROY && logAllNamedEntityKills && entity.getCustomName() != null) {
return true;
}
return false;
}
public boolean isLoggingAnyEntities() {
return logAll || logAnimals || logLiving || logMonsters || !logged.isEmpty() || (entityAction == EntityLogging.DESTROY && logAllNamedEntityKills);
}
}
}

View File

@ -19,9 +19,7 @@ public class BlockChangePreLogEvent extends PreLogEvent {
private YamlConfiguration stateBefore;
private YamlConfiguration stateAfter;
public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefore, BlockData typeAfter,
YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess chestAccess) {
public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefore, BlockData typeAfter, YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess chestAccess) {
super(owner);
this.location = location;
this.typeBefore = typeBefore;
@ -32,17 +30,14 @@ public class BlockChangePreLogEvent extends PreLogEvent {
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public BlockData getTypeBefore() {
return typeBefore;
}
@ -54,7 +49,6 @@ public class BlockChangePreLogEvent extends PreLogEvent {
}
public BlockData getTypeAfter() {
return typeAfter;
}
@ -82,22 +76,19 @@ public class BlockChangePreLogEvent extends PreLogEvent {
}
public ChestAccess getChestAccess() {
return chestAccess;
}
public void setChestAccess(ChestAccess chestAccess) {
this.chestAccess = chestAccess;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -0,0 +1,54 @@
package de.diddiz.LogBlock.events;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.EntityChange.EntityChangeType;
import org.bukkit.Location;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.event.HandlerList;
public class EntityChangePreLogEvent extends PreLogEvent {
private static final HandlerList handlers = new HandlerList();
private Location location;
private Entity entity;
private EntityChangeType changeType;
private YamlConfiguration changeData;
public EntityChangePreLogEvent(Actor owner, Location location, Entity entity, EntityChangeType changeType, YamlConfiguration changeData) {
super(owner);
this.location = location;
this.entity = entity;
this.changeType = changeType;
this.changeData = changeData;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public Entity getEntity() {
return entity;
}
public EntityChangeType getChangeType() {
return changeType;
}
public YamlConfiguration getChangeData() {
return changeData;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -10,7 +10,6 @@ public abstract class PreLogEvent extends Event implements Cancellable {
protected Actor owner;
public PreLogEvent(Actor owner) {
this.owner = owner;
}
@ -21,8 +20,8 @@ public abstract class PreLogEvent extends Event implements Cancellable {
* @deprecated {@link #getOwnerActor() } returns an object encapsulating
* name and uuid. Names are not guaranteed to be unique.
*/
@Deprecated
public String getOwner() {
return owner.getName();
}
@ -41,17 +40,16 @@ public abstract class PreLogEvent extends Event implements Cancellable {
* @param owner The player/monster/cause who is involved in this event
*/
public void setOwner(Actor owner) {
this.owner = owner;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -0,0 +1,59 @@
package de.diddiz.LogBlock.events;
import de.diddiz.LogBlock.QueryParams;
import de.diddiz.LogBlock.Tool;
import de.diddiz.LogBlock.ToolBehavior;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
/**
* Fired whether a tool is about to be used by a player.
*/
public class ToolUseEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel;
private final Tool tool;
private final ToolBehavior behavior;
private final QueryParams params;
public ToolUseEvent(Player who, Tool tool, ToolBehavior behavior, QueryParams params) {
super(who);
this.tool = tool;
this.behavior = behavior;
this.params = params;
}
@Override
public boolean isCancelled() {
return cancel;
}
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
public Tool getTool() {
return tool;
}
public ToolBehavior getBehavior() {
return behavior;
}
public QueryParams getParams() {
return params;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -5,7 +5,10 @@ import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Bee;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.ItemFrame;
@ -22,6 +25,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityPlaceEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
@ -38,7 +42,8 @@ import de.diddiz.LogBlock.EntityChange.EntityChangeType;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.config.EntityLogging;
import de.diddiz.worldedit.WorldEditHelper;
import de.diddiz.LogBlock.util.LoggingUtil;
import de.diddiz.LogBlock.worldedit.WorldEditHelper;
import java.util.UUID;
public class AdvancedEntityLogging extends LoggingListener {
@ -50,6 +55,7 @@ public class AdvancedEntityLogging extends LoggingListener {
// serialize them before the death event
private UUID lastEntityDamagedForDeathUUID;
private byte[] lastEntityDamagedForDeathSerialized;
private Entity lastEntityDamagedForDeathDamager;
public AdvancedEntityLogging(LogBlock lb) {
super(lb);
@ -67,6 +73,7 @@ public class AdvancedEntityLogging extends LoggingListener {
lastSpawnerEgg = false;
lastEntityDamagedForDeathUUID = null;
lastEntityDamagedForDeathSerialized = null;
lastEntityDamagedForDeathDamager = null;
}
private void setLastSpawner(Player player, Class<? extends Entity> spawning, boolean spawnEgg) {
@ -124,7 +131,7 @@ public class AdvancedEntityLogging extends LoggingListener {
inHand = inHand.clone();
inHand.setAmount(1);
data.set("item", inHand);
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.ADDEQUIP, data);
consumer.queueEntityModification(actor, entity, EntityChange.EntityChangeType.ADDEQUIP, data);
}
}
}
@ -134,9 +141,13 @@ public class AdvancedEntityLogging extends LoggingListener {
@EventHandler(priority = EventPriority.MONITOR)
public void onEntitySpawn(CreatureSpawnEvent event) {
if (!event.isCancelled()) {
if (event.getSpawnReason() == SpawnReason.CUSTOM) {
if (event.getSpawnReason() == SpawnReason.CUSTOM || event.getSpawnReason() == SpawnReason.BEEHIVE) {
return;
}
if (event.getEntityType() == EntityType.ARMOR_STAND) {
resetOnTick();
return; // logged in the method below
}
LivingEntity entity = event.getEntity();
if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) {
Actor actor = null;
@ -148,6 +159,9 @@ public class AdvancedEntityLogging extends LoggingListener {
}
}
if (actor == null) {
if (event.getSpawnReason() == SpawnReason.NATURAL && !Config.isLoggingNatualSpawns(entity.getWorld())) {
return;
}
actor = new Actor(event.getSpawnReason().toString());
}
queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE);
@ -156,6 +170,23 @@ public class AdvancedEntityLogging extends LoggingListener {
resetOnTick();
}
@EventHandler(priority = EventPriority.MONITOR)
public void onEntityPlace(EntityPlaceEvent event) {
if (!event.isCancelled()) {
Entity entity = event.getEntity();
if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) {
Actor actor = null;
if (event.getPlayer() != null) {
actor = Actor.actorFromEntity(event.getPlayer());
}
if (actor == null) {
actor = new Actor("UNKNOWN");
}
queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent event) {
LivingEntity entity = event.getEntity();
@ -163,11 +194,14 @@ public class AdvancedEntityLogging extends LoggingListener {
Actor actor = null;
EntityDamageEvent lastDamage = entity.getLastDamageCause();
if (lastDamage instanceof EntityDamageByEntityEvent) {
Entity damager = ((EntityDamageByEntityEvent) lastDamage).getDamager();
Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) lastDamage).getDamager());
if (damager != null) {
actor = Actor.actorFromEntity(damager);
}
}
if (actor == null && entity.getKiller() != null) {
actor = Actor.actorFromEntity(entity.getKiller());
}
if (actor == null) {
actor = new Actor(lastDamage == null ? "UNKNOWN" : lastDamage.getCause().toString());
}
@ -190,7 +224,8 @@ public class AdvancedEntityLogging extends LoggingListener {
if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) {
Actor actor;
if (event instanceof HangingBreakByEntityEvent) {
actor = Actor.actorFromEntity(((HangingBreakByEntityEvent) event).getRemover());
Entity damager = LoggingUtil.getRealDamager(((HangingBreakByEntityEvent) event).getRemover());
actor = Actor.actorFromEntity(damager);
} else {
actor = new Actor(event.getCause().toString());
}
@ -207,13 +242,14 @@ public class AdvancedEntityLogging extends LoggingListener {
if (Config.isLogging(entity.getWorld(), EntityLogging.MODIFY, entity)) {
Actor actor;
if (event instanceof EntityDamageByEntityEvent) {
actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) event).getDamager());
Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) event).getDamager());
actor = Actor.actorFromEntity(damager);
} else {
actor = new Actor(event.getCause().toString());
}
YamlConfiguration data = new YamlConfiguration();
data.set("item", oldItem);
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.REMOVEEQUIP, data);
consumer.queueEntityModification(actor, entity, EntityChange.EntityChangeType.REMOVEEQUIP, data);
}
}
}
@ -221,6 +257,29 @@ public class AdvancedEntityLogging extends LoggingListener {
lastEntityDamagedForDeathUUID = entity.getUniqueId();
lastEntityDamagedForDeathSerialized = WorldEditHelper.serializeEntity(entity);
}
if (entity instanceof EnderCrystal) {
if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) {
if (event instanceof EntityDamageByEntityEvent) {
Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) event).getDamager());
if (lastEntityDamagedForDeathDamager == null || !(damager instanceof EnderCrystal)) {
lastEntityDamagedForDeathDamager = damager;
}
}
Actor actor = lastEntityDamagedForDeathDamager != null ? Actor.actorFromEntity(lastEntityDamagedForDeathDamager) : new Actor(event.getCause().toString());
queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
Entity damager = event.getDamager();
if (damager instanceof Bee && !((Bee) damager).hasStung()) {
if (Config.isLogging(damager.getWorld(), EntityLogging.MODIFY, damager)) {
Actor actor = Actor.actorFromEntity(event.getEntity());
consumer.queueEntityModification(actor, damager, EntityChange.EntityChangeType.GET_STUNG, null);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@ -239,13 +298,13 @@ public class AdvancedEntityLogging extends LoggingListener {
YamlConfiguration data = new YamlConfiguration();
data.set("item", oldItem);
data.set("slot", event.getSlot().name());
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.REMOVEEQUIP, data);
consumer.queueEntityModification(actor, entity, EntityChange.EntityChangeType.REMOVEEQUIP, data);
}
if (!newEmpty) {
YamlConfiguration data = new YamlConfiguration();
data.set("item", newItem);
data.set("slot", event.getSlot().name());
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.ADDEQUIP, data);
consumer.queueEntityModification(actor, entity, EntityChange.EntityChangeType.ADDEQUIP, data);
}
}
}
@ -263,6 +322,6 @@ public class AdvancedEntityLogging extends LoggingListener {
} else {
data.set("worldedit", WorldEditHelper.serializeEntity(entity));
}
consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, changeType, data);
consumer.queueEntityModification(actor, entity, changeType, data);
}
}

View File

@ -1,48 +1,48 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.CommandsHandler;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.QueryParams;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import static de.diddiz.LogBlock.config.Config.banPermission;
import static de.diddiz.LogBlock.config.Config.isLogged;
import static org.bukkit.Bukkit.getScheduler;
public class BanListener implements Listener {
private final CommandsHandler handler;
private final LogBlock logblock;
public BanListener(LogBlock logblock) {
this.logblock = logblock;
handler = logblock.getCommandsHandler();
}
@EventHandler
public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) {
final String[] split = event.getMessage().split(" ");
if (split.length > 1 && split[0].equalsIgnoreCase("/ban") && logblock.hasPermission(event.getPlayer(), banPermission)) {
final QueryParams p = new QueryParams(logblock);
p.setPlayer(split[1].equalsIgnoreCase("g") ? split[2] : split[1]);
p.since = 0;
p.silent = false;
getScheduler().runTaskAsynchronously(logblock, new Runnable() {
@Override
public void run() {
for (final World world : logblock.getServer().getWorlds()) {
if (isLogged(world)) {
p.world = world;
try {
handler.new CommandRollback(event.getPlayer(), p, false);
} catch (final Exception ex) {
}
}
}
}
});
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.CommandsHandler;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.QueryParams;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import static de.diddiz.LogBlock.config.Config.banPermission;
import static de.diddiz.LogBlock.config.Config.isLogged;
import static org.bukkit.Bukkit.getScheduler;
public class BanListener implements Listener {
private final CommandsHandler handler;
private final LogBlock logblock;
public BanListener(LogBlock logblock) {
this.logblock = logblock;
handler = logblock.getCommandsHandler();
}
@EventHandler
public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) {
final String[] split = event.getMessage().split(" ");
if (split.length > 1 && split[0].equalsIgnoreCase("/ban") && logblock.hasPermission(event.getPlayer(), banPermission)) {
final QueryParams p = new QueryParams(logblock);
p.setPlayer(split[1].equalsIgnoreCase("g") ? split[2] : split[1]);
p.since = 0;
p.silent = false;
getScheduler().runTaskAsynchronously(logblock, new Runnable() {
@Override
public void run() {
for (final World world : logblock.getServer().getWorlds()) {
if (isLogged(world)) {
p.world = world;
try {
handler.new CommandRollback(event.getPlayer(), p, false);
} catch (final Exception ex) {
}
}
}
}
});
}
}
}

View File

@ -1,77 +1,88 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.util.BukkitUtils;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerBucketFillEvent;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.util.LoggingUtil.smartLogBlockBreak;
import static de.diddiz.util.LoggingUtil.smartLogFallables;
public class BlockBreakLogging extends LoggingListener {
public BlockBreakLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.BLOCKBREAK)) {
WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
if (wcfg == null) {
return;
}
final Actor actor = Actor.actorFromEntity(event.getPlayer());
final Block origin = event.getBlock();
final Material type = origin.getType();
if (wcfg.isLogging(Logging.SIGNTEXT) && (type == Material.SIGN || type == Material.WALL_SIGN)) {
consumer.queueSignBreak(actor, (Sign) origin.getState());
} else if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type)) {
consumer.queueContainerBreak(actor, origin.getState());
} else if (type == Material.ICE) {
// When in creative mode ice doesn't form water
if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) {
consumer.queueBlockBreak(actor, origin.getState());
} else {
consumer.queueBlockReplace(actor, origin.getState(), Bukkit.createBlockData(Material.WATER));
}
} else {
smartLogBlockBreak(consumer, actor, origin);
}
smartLogFallables(consumer, actor, origin);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerBucketFill(PlayerBucketFillEvent event) {
if (isLogging(event.getBlockClicked().getWorld(), Logging.BLOCKBREAK)) {
BlockData clickedBlockData = event.getBlockClicked().getBlockData();
if (clickedBlockData instanceof Waterlogged) {
Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData;
if (clickedWaterlogged.isWaterlogged()) {
Waterlogged clickedWaterloggedWithoutWater = (Waterlogged) clickedWaterlogged.clone();
clickedWaterloggedWithoutWater.setWaterlogged(false);
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithoutWater);
}
} else {
consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState());
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.LogBlock.util.BukkitUtils;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.event.player.PlayerBucketFillEvent;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockReplace;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables;
public class BlockBreakLogging extends LoggingListener {
public BlockBreakLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.BLOCKBREAK)) {
WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
if (wcfg == null) {
return;
}
final Actor actor = Actor.actorFromEntity(event.getPlayer());
final Block origin = event.getBlock();
final Material type = origin.getType();
if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.isContainerBlock(type) && !BukkitUtils.isShulkerBoxBlock(type)) {
consumer.queueContainerBreak(actor, origin.getState());
} else if (type == Material.ICE) {
// When in creative mode ice doesn't form water
if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) {
smartLogBlockBreak(consumer, actor, origin);
} else {
smartLogBlockReplace(consumer, actor, origin, Bukkit.createBlockData(Material.WATER));
}
} else {
smartLogBlockBreak(consumer, actor, origin);
}
smartLogFallables(consumer, actor, origin);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerBucketFill(PlayerBucketFillEvent event) {
if (isLogging(event.getBlockClicked().getWorld(), Logging.BLOCKBREAK)) {
BlockData clickedBlockData = event.getBlockClicked().getBlockData();
if (clickedBlockData instanceof Waterlogged) {
Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData;
if (clickedWaterlogged.isWaterlogged()) {
Waterlogged clickedWaterloggedWithoutWater = (Waterlogged) clickedWaterlogged.clone();
clickedWaterloggedWithoutWater.setWaterlogged(false);
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithoutWater);
}
} else {
consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState());
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockDropItem(BlockDropItemEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.BLOCKBREAK)) {
Material type = event.getBlock().getType();
if (type == Material.SUSPICIOUS_GRAVEL || type == Material.SUSPICIOUS_SAND) {
Material simplyBroken = type == Material.SUSPICIOUS_SAND ? Material.SAND : Material.GRAVEL;
if (event.getItems().size() != 1 || event.getItems().get(0).getItemStack().getType() != simplyBroken) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockState(), simplyBroken.createBlockData());
}
}
}
}
}

View File

@ -1,72 +1,72 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
import org.bukkit.event.player.PlayerInteractEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.util.LoggingUtil.smartLogBlockBreak;
import static de.diddiz.util.LoggingUtil.smartLogBlockReplace;
import static de.diddiz.util.LoggingUtil.smartLogFallables;
public class BlockBurnLogging extends LoggingListener {
public BlockBurnLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBurn(BlockBurnEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) {
smartLogBlockReplace(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock(), Material.FIRE.createBlockData());
smartLogFallables(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock());
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockIgnite(BlockIgniteEvent event) {
Actor actor = new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null);
if (event.getCause() == IgniteCause.FLINT_AND_STEEL) {
if (event.getIgnitingEntity() != null) {
return; // handled in block place
} else {
actor = new Actor("Dispenser");
}
} else if(event.getCause() == IgniteCause.LIGHTNING) {
actor = new Actor("Lightning");
} else if(event.getCause() == IgniteCause.EXPLOSION) {
actor = new Actor("Explosion");
} else if(event.getCause() == IgniteCause.LAVA) {
actor = new Actor("Lava");
} else if(event.getCause() == IgniteCause.ENDER_CRYSTAL) {
actor = new Actor("EnderCrystal");
}
if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) {
consumer.queueBlockPlace(actor, event.getBlock().getLocation(), Material.FIRE.createBlockData());
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onExtinguish(PlayerInteractEvent event) {
if (event.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
Player player = event.getPlayer();
Block block = event.getClickedBlock().getRelative(event.getBlockFace());
if (block.getType().equals(Material.FIRE) && isLogging(player.getWorld(), Logging.FIRE)) {
Actor actor = Actor.actorFromEntity(player);
smartLogBlockBreak(consumer, actor, block);
smartLogFallables(consumer, actor, block);
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
import org.bukkit.event.player.PlayerInteractEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockReplace;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables;
public class BlockBurnLogging extends LoggingListener {
public BlockBurnLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBurn(BlockBurnEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) {
smartLogBlockReplace(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock(), Material.FIRE.createBlockData());
smartLogFallables(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock());
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockIgnite(BlockIgniteEvent event) {
Actor actor = new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null);
if (event.getCause() == IgniteCause.FLINT_AND_STEEL) {
if (event.getIgnitingEntity() != null) {
return; // handled in block place
} else {
actor = new Actor("Dispenser");
}
} else if (event.getCause() == IgniteCause.LIGHTNING) {
actor = new Actor("Lightning");
} else if (event.getCause() == IgniteCause.EXPLOSION) {
actor = new Actor("Explosion");
} else if (event.getCause() == IgniteCause.LAVA) {
actor = new Actor("Lava");
} else if (event.getCause() == IgniteCause.ENDER_CRYSTAL) {
actor = new Actor("EnderCrystal");
}
if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) {
consumer.queueBlockPlace(actor, event.getBlock().getLocation(), Material.FIRE.createBlockData());
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onExtinguish(PlayerInteractEvent event) {
if (event.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
Player player = event.getPlayer();
Block block = event.getClickedBlock().getRelative(event.getBlockFace());
if (block.getType().equals(Material.FIRE) && isLogging(player.getWorld(), Logging.FIRE)) {
Actor actor = Actor.actorFromEntity(player);
smartLogBlockBreak(consumer, actor, block);
smartLogFallables(consumer, actor, block);
}
}
}
}

View File

@ -0,0 +1,36 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import org.bukkit.block.BlockState;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFertilizeEvent;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
public class BlockFertilizeLogging extends LoggingListener {
public BlockFertilizeLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockFertilize(BlockFertilizeEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getBlock().getLocation().getWorld());
if (wcfg != null) {
if (!wcfg.isLogging(Logging.BONEMEALSTRUCTUREGROW)) {
return;
}
final Actor actor;
if (event.getPlayer() != null) {
actor = Actor.actorFromEntity(event.getPlayer());
} else {
actor = new Actor("Dispenser");
}
for (final BlockState state : event.getBlocks()) {
consumer.queueBlockReplace(actor, state.getBlock().getState(), state);
}
}
}
}

View File

@ -1,59 +1,67 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.util.LoggingUtil;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class BlockPlaceLogging extends LoggingListener {
public BlockPlaceLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent event) {
if (Config.isLogging(event.getBlock().getWorld(), Logging.BLOCKPLACE)) {
final BlockState before = event.getBlockReplacedState();
final BlockState after = event.getBlockPlaced().getState();
final Actor actor = Actor.actorFromEntity(event.getPlayer());
LoggingUtil.smartLogBlockPlace(consumer, actor, before, after);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) {
Material placedMaterial = event.getBucket() == Material.LAVA_BUCKET ? Material.LAVA : Material.WATER;
BlockData clickedBlockData = event.getBlockClicked().getBlockData();
if (placedMaterial == Material.WATER && clickedBlockData instanceof Waterlogged) {
Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData;
if (!clickedWaterlogged.isWaterlogged()) {
Waterlogged clickedWaterloggedWithWater = (Waterlogged) clickedWaterlogged.clone();
clickedWaterloggedWithWater.setWaterlogged(true);
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithWater);
return;
}
}
Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace());
if (placedAt.isEmpty()) {
consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData());
} else {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAt.getBlockData(), placedMaterial.createBlockData());
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.util.LoggingUtil;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class BlockPlaceLogging extends LoggingListener {
public BlockPlaceLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent event) {
if (Config.isLogging(event.getBlock().getWorld(), Logging.BLOCKPLACE)) {
final BlockState before = event.getBlockReplacedState();
final BlockState after = event.getBlockPlaced().getState();
final Actor actor = Actor.actorFromEntity(event.getPlayer());
if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) {
return;
}
LoggingUtil.smartLogBlockPlace(consumer, actor, before, after);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) {
Material placedMaterial = event.getBucket() == Material.LAVA_BUCKET ? Material.LAVA : Material.WATER;
BlockData clickedBlockData = event.getBlockClicked().getBlockData();
if (placedMaterial == Material.WATER && clickedBlockData instanceof Waterlogged) {
Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData;
if (!clickedWaterlogged.isWaterlogged()) {
Waterlogged clickedWaterloggedWithWater = (Waterlogged) clickedWaterlogged.clone();
clickedWaterloggedWithWater.setWaterlogged(true);
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithWater);
return;
}
}
Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace());
if (placedAt.isEmpty()) {
consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData());
} else {
BlockData placedAtBlock = placedAt.getBlockData();
if (placedAtBlock instanceof Waterlogged && !(((Waterlogged) placedAtBlock).isWaterlogged())) {
Waterlogged clickedWaterloggedWithWater = (Waterlogged) placedAtBlock.clone();
clickedWaterloggedWithWater.setWaterlogged(true);
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, clickedWaterloggedWithWater);
} else {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, placedMaterial.createBlockData());
}
}
}
}
}

View File

@ -5,6 +5,10 @@ import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.PointedDripstone;
import org.bukkit.block.data.type.PointedDripstone.Thickness;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockSpreadEvent;
@ -22,37 +26,74 @@ public class BlockSpreadLogging extends LoggingListener {
String name;
World world = event.getBlock().getWorld();
Material type = event.getSource().getType();
World world = event.getNewState().getWorld();
Material type = event.getNewState().getType();
switch (type) {
case GRASS:
if (!isLogging(world, Logging.GRASSGROWTH)) {
return;
}
name = "GrassGrowth";
break;
case MYCELIUM:
if (!isLogging(world, Logging.MYCELIUMSPREAD)) {
return;
}
name = "MyceliumSpread";
break;
case VINE:
if (!isLogging(world, Logging.VINEGROWTH)) {
return;
}
name = "VineGrowth";
break;
case RED_MUSHROOM:
case BROWN_MUSHROOM:
if (!isLogging(world, Logging.MUSHROOMSPREAD)) {
return;
}
name = "MushroomSpread";
break;
default:
if (type == Material.SHORT_GRASS) {
if (!isLogging(world, Logging.GRASSGROWTH)) {
return;
}
name = "GrassGrowth";
} else if (type == Material.MYCELIUM) {
if (!isLogging(world, Logging.MYCELIUMSPREAD)) {
return;
}
name = "MyceliumSpread";
} else if (type == Material.VINE || type == Material.CAVE_VINES || type == Material.CAVE_VINES_PLANT || type == Material.WEEPING_VINES || type == Material.WEEPING_VINES_PLANT || type == Material.TWISTING_VINES || type == Material.TWISTING_VINES_PLANT) {
if (!isLogging(world, Logging.VINEGROWTH)) {
return;
}
name = "VineGrowth";
} else if (type == Material.RED_MUSHROOM || type == Material.BROWN_MUSHROOM) {
if (!isLogging(world, Logging.MUSHROOMSPREAD)) {
return;
}
name = "MushroomSpread";
} else if (type == Material.BAMBOO || type == Material.BAMBOO_SAPLING) {
if (!isLogging(world, Logging.BAMBOOGROWTH)) {
return;
}
name = "BambooGrowth";
if (type == Material.BAMBOO_SAPLING) {
// bamboo sapling gets replaced by bamboo
consumer.queueBlockReplace(new Actor(name), event.getSource().getState(), Material.BAMBOO.createBlockData());
}
} else if (type == Material.POINTED_DRIPSTONE) {
if (!isLogging(world, Logging.DRIPSTONEGROWTH)) {
return;
}
name = "DripstoneGrowth";
PointedDripstone pointed = (PointedDripstone) event.getNewState().getBlockData();
if (pointed.getThickness() != Thickness.TIP_MERGE) {
BlockFace direction = pointed.getVerticalDirection();
Block previousPart = event.getBlock().getRelative(direction.getOppositeFace());
if (previousPart.getType() == Material.POINTED_DRIPSTONE) {
PointedDripstone newBelow = (PointedDripstone) previousPart.getBlockData();
newBelow.setThickness(Thickness.FRUSTUM);
consumer.queueBlockReplace(new Actor(name), previousPart.getState(), newBelow);
previousPart = previousPart.getRelative(direction.getOppositeFace());
if (previousPart.getType() == Material.POINTED_DRIPSTONE) {
Block evenMorePrevious = previousPart.getRelative(direction.getOppositeFace());
newBelow = (PointedDripstone) previousPart.getBlockData();
newBelow.setThickness(evenMorePrevious.getType() == Material.POINTED_DRIPSTONE ? Thickness.MIDDLE : Thickness.BASE);
consumer.queueBlockReplace(new Actor(name), previousPart.getState(), newBelow);
}
}
} else {
// special case because the old state is already changed (for one half)
PointedDripstone oldState = (PointedDripstone) event.getNewState().getBlockData();
oldState.setThickness(Thickness.TIP);
consumer.queueBlockReplace(new Actor(name), oldState, event.getNewState());
return;
}
} else if (type == Material.SCULK || type == Material.SCULK_VEIN || type == Material.SCULK_CATALYST || type == Material.SCULK_SENSOR || type == Material.SCULK_SHRIEKER) {
if (!isLogging(world, Logging.SCULKSPREAD)) {
return;
}
name = "SculkSpread";
} else {
return;
}
consumer.queueBlockReplace(new Actor(name), event.getBlock().getState(), event.getNewState());

View File

@ -0,0 +1,27 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.CauldronLevelChangeEvent;
public class CauldronLogging extends LoggingListener {
public CauldronLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onCauldronLevelChange(CauldronLevelChangeEvent event) {
if (Config.isLogging(event.getBlock().getWorld(), Logging.CAULDRONINTERACT)) {
Entity causingEntity = event.getEntity();
if (causingEntity instanceof Player) {
consumer.queueBlockReplace(Actor.actorFromEntity(causingEntity), event.getBlock().getBlockData(), event.getNewState());
}
}
}
}

View File

@ -1,37 +1,58 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class ChatLogging extends LoggingListener {
public ChatLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) {
consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage());
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerChat(AsyncPlayerChatEvent event) {
if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) {
consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage());
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onServerCommand(ServerCommandEvent event) {
consumer.queueChat(new Actor("Console"), "/" + event.getCommand());
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.minecart.CommandMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class ChatLogging extends LoggingListener {
public ChatLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
if (isLogging(event.getPlayer().getWorld(), Logging.PLAYER_COMMANDS)) {
consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage());
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerChat(AsyncPlayerChatEvent event) {
if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) {
consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage());
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onServerCommand(ServerCommandEvent event) {
CommandSender sender = event.getSender();
Actor actor;
if (sender instanceof BlockCommandSender) {
if (!isLogging(((BlockCommandSender) sender).getBlock().getWorld(), Logging.COMMANDBLOCK_COMMANDS)) {
return;
}
actor = new Actor("CommandBlock");
} else if (sender instanceof CommandMinecart) {
if (!isLogging(((CommandMinecart) sender).getWorld(), Logging.COMMANDBLOCK_COMMANDS)) {
return;
}
actor = new Actor("CommandMinecart");
} else {
if (!isLogging(Logging.CONSOLE_COMMANDS)) {
return;
}
actor = new Actor("Console");
}
consumer.queueChat(actor, "/" + event.getCommand());
}
}

View File

@ -1,72 +1,303 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.DoubleChest;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.util.BukkitUtils.*;
public class ChestAccessLogging extends LoggingListener {
private final Map<HumanEntity, ItemStack[]> containers = new HashMap<HumanEntity, ItemStack[]>();
public ChestAccessLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClose(InventoryCloseEvent event) {
if (!isLogging(event.getPlayer().getWorld(), Logging.CHESTACCESS)) {
return;
}
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState || holder instanceof DoubleChest) {
final HumanEntity player = event.getPlayer();
final ItemStack[] before = containers.get(player);
if (before != null) {
final ItemStack[] after = compressInventory(event.getInventory().getContents());
final ItemStack[] diff = compareInventories(before, after);
final Location loc = getInventoryHolderLocation(holder);
if (loc != null) {
for (final ItemStack item : diff) {
ItemStack item2 = item.clone();
item2.setAmount(Math.abs(item.getAmount()));
consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockAt(loc).getBlockData(), item2, item.getAmount() < 0);
}
}
containers.remove(player);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryOpen(InventoryOpenEvent event) {
if (!isLogging(event.getPlayer().getWorld(), Logging.CHESTACCESS)) {
return;
}
if (event.getInventory() != null) {
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState || holder instanceof DoubleChest) {
if (getInventoryHolderType(holder) != Material.CRAFTING_TABLE) {
containers.put(event.getPlayer(), compressInventory(event.getInventory().getContents()));
}
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.DoubleChest;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
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.Map;
import java.util.Map.Entry;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.LogBlock.util.BukkitUtils.*;
public class ChestAccessLogging extends LoggingListener {
private class PlayerActiveInventoryModifications {
private final HumanEntity actor;
private final Location location;
private final HashMap<ItemStack, Integer> modifications;
public PlayerActiveInventoryModifications(HumanEntity actor, Location location) {
this.actor = actor;
this.location = location;
this.modifications = new HashMap<>();
}
public void addModification(ItemStack stack, int amount) {
if (amount == 0) {
return;
}
// if we have other viewers, we have to flush their changes
ArrayList<PlayerActiveInventoryModifications> allViewers = containersByLocation.get(location);
if (allViewers.size() > 1) {
for (PlayerActiveInventoryModifications other : allViewers) {
if (other != this) {
other.flush();
}
}
}
// consumer.getLogblock().getLogger().info("Modify container: " + stack + " change: " + amount);
stack = new ItemStack(stack);
stack.setAmount(1);
Integer existing = modifications.get(stack);
int newTotal = amount + (existing == null ? 0 : existing);
if (newTotal == 0) {
modifications.remove(stack);
} else {
modifications.put(stack, newTotal);
}
}
public void flush() {
if (!modifications.isEmpty()) {
for (Entry<ItemStack, Integer> e : modifications.entrySet()) {
ItemStack stack = e.getKey();
int amount = e.getValue();
stack.setAmount(Math.abs(amount));
// consumer.getLogblock().getLogger().info("Store container: " + stack + " take: " + (amount < 0));
consumer.queueChestAccess(Actor.actorFromEntity(actor), location, location.getWorld().getBlockAt(location).getBlockData(), stack, amount < 0);
}
modifications.clear();
}
}
public HumanEntity getActor() {
return actor;
}
public Location getLocation() {
return location;
}
}
private final Map<HumanEntity, PlayerActiveInventoryModifications> containersByOwner = new HashMap<>();
private final Map<Location, ArrayList<PlayerActiveInventoryModifications>> containersByLocation = new HashMap<>();
public ChestAccessLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClose(InventoryCloseEvent event) {
final HumanEntity player = event.getPlayer();
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
return;
}
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState || holder instanceof DoubleChest) {
final PlayerActiveInventoryModifications modifications = containersByOwner.remove(player);
if (modifications != null) {
final Location loc = modifications.getLocation();
ArrayList<PlayerActiveInventoryModifications> atLocation = containersByLocation.get(loc);
atLocation.remove(modifications);
if (atLocation.isEmpty()) {
containersByLocation.remove(loc);
}
modifications.flush();
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryOpen(InventoryOpenEvent event) {
final HumanEntity player = event.getPlayer();
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
return;
}
if (event.getInventory() != null) {
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState || holder instanceof DoubleChest) {
if (getInventoryHolderType(holder) != Material.CRAFTING_TABLE) {
PlayerActiveInventoryModifications modifications = new PlayerActiveInventoryModifications(event.getPlayer(), getInventoryHolderLocation(holder));
containersByOwner.put(modifications.getActor(), modifications);
containersByLocation.compute(modifications.getLocation(), (k, v) -> {
if (v == null) {
v = new ArrayList<>();
}
v.add(modifications);
return v;
});
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent event) {
final HumanEntity player = event.getWhoClicked();
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
return;
}
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState || holder instanceof DoubleChest) {
final PlayerActiveInventoryModifications modifications = containersByOwner.get(player);
if (modifications != null) {
switch (event.getAction()) {
case PICKUP_ONE:
case DROP_ONE_SLOT:
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
modifications.addModification(event.getCurrentItem(), -1);
}
break;
case PICKUP_HALF:
// server behaviour: round up
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
modifications.addModification(event.getCurrentItem(), -(event.getCurrentItem().getAmount() + 1) / 2);
}
break;
case PICKUP_SOME: // oversized stack - can not take all when clicking
// server behaviour: leave a full stack in the slot, take everything else
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
int taken = event.getCurrentItem().getAmount() - event.getCurrentItem().getMaxStackSize();
modifications.addModification(event.getCursor(), -taken);
}
break;
case PICKUP_ALL:
case DROP_ALL_SLOT:
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount());
}
break;
case PLACE_ONE:
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
modifications.addModification(event.getCursor(), 1);
}
break;
case PLACE_SOME: // not enough free place in target slot
// server behaviour: place as much as possible
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
int placeable = event.getCurrentItem().getMaxStackSize() - event.getCurrentItem().getAmount();
modifications.addModification(event.getCursor(), placeable);
}
break;
case PLACE_ALL:
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
modifications.addModification(event.getCursor(), event.getCursor().getAmount());
}
break;
case SWAP_WITH_CURSOR:
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
modifications.addModification(event.getCursor(), event.getCursor().getAmount());
modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount());
}
break;
case MOVE_TO_OTHER_INVENTORY: // shift + click
boolean removed = event.getRawSlot() < event.getView().getTopInventory().getSize();
modifications.addModification(event.getCurrentItem(), event.getCurrentItem().getAmount() * (removed ? -1 : 1));
break;
case COLLECT_TO_CURSOR: // double click
// server behaviour: first collect all with an amount != maxstacksize, then others, starting from slot 0 (container)
ItemStack cursor = event.getCursor();
if (cursor == null) {
return;
}
int toPickUp = cursor.getMaxStackSize() - cursor.getAmount();
int takenFromContainer = 0;
boolean takeFromFullStacks = false;
Inventory top = event.getView().getTopInventory();
Inventory bottom = event.getView().getBottomInventory();
while (toPickUp > 0) {
for (ItemStack stack : top.getStorageContents()) {
if (cursor.isSimilar(stack)) {
if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) {
int take = Math.min(toPickUp, stack.getAmount());
toPickUp -= take;
takenFromContainer += take;
if (toPickUp <= 0) {
break;
}
}
}
}
if (toPickUp <= 0) {
break;
}
for (ItemStack stack : bottom.getStorageContents()) {
if (cursor.isSimilar(stack)) {
if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) {
int take = Math.min(toPickUp, stack.getAmount());
toPickUp -= take;
if (toPickUp <= 0) {
break;
}
}
}
}
if (takeFromFullStacks) {
break;
} else {
takeFromFullStacks = true;
}
}
if (takenFromContainer > 0) {
modifications.addModification(event.getCursor(), -takenFromContainer);
}
break;
case HOTBAR_SWAP: // number key or offhand key
case HOTBAR_MOVE_AND_READD: // something was in the other slot
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
ItemStack otherSlot = (event.getClick() == ClickType.SWAP_OFFHAND) ? event.getWhoClicked().getInventory().getItemInOffHand() : event.getWhoClicked().getInventory().getItem(event.getHotbarButton());
if (event.getCurrentItem() != null && event.getCurrentItem().getType() != Material.AIR) {
modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount());
}
if (otherSlot != null && otherSlot.getType() != Material.AIR) {
modifications.addModification(otherSlot, otherSlot.getAmount());
}
}
break;
case DROP_ALL_CURSOR:
case DROP_ONE_CURSOR:
case CLONE_STACK:
case NOTHING:
// only the cursor or nothing (but not the inventory) was modified
break;
case UNKNOWN:
default:
// unable to log something we don't know
consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType());
break;
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryDrag(InventoryDragEvent event) {
final HumanEntity player = event.getWhoClicked();
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
return;
}
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState || holder instanceof DoubleChest) {
final PlayerActiveInventoryModifications modifications = containersByOwner.get(player);
if (modifications != null) {
Inventory container = event.getView().getTopInventory();
int containerSize = container.getSize();
for (Entry<Integer, ItemStack> e : event.getNewItems().entrySet()) {
int slot = e.getKey();
if (slot < containerSize) {
ItemStack old = container.getItem(slot);
int oldAmount = (old == null || old.getType() == Material.AIR) ? 0 : old.getAmount();
modifications.addModification(e.getValue(), e.getValue().getAmount() - oldAmount);
}
}
}
}
}
}

View File

@ -4,13 +4,12 @@ import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.util.BukkitUtils;
import de.diddiz.LogBlock.util.BukkitUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.TurtleEgg;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@ -27,10 +26,8 @@ public class CreatureInteractLogging extends LoggingListener {
public void onEntityInteract(EntityInteractEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getEntity().getWorld());
final EntityType entityType = event.getEntityType();
// Mobs only
if (event.getEntity() instanceof Player || entityType == null) {
if (event.getEntity() instanceof Player) {
return;
}
@ -42,10 +39,10 @@ public class CreatureInteractLogging extends LoggingListener {
if (type == Material.FARMLAND) {
if (wcfg.isLogging(Logging.CREATURECROPTRAMPLE)) {
// 3 = Dirt ID
consumer.queueBlock(Actor.actorFromEntity(entityType), loc, type.createBlockData(), Material.DIRT.createBlockData());
consumer.queueBlock(new Actor("CreatureTrample"), loc, type.createBlockData(), Material.DIRT.createBlockData());
// Log the crop on top as being broken
Block trampledCrop = clicked.getRelative(BlockFace.UP);
if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) {
if (BukkitUtils.isCropBlock(trampledCrop.getType())) {
consumer.queueBlockBreak(new Actor("CreatureTrample"), trampledCrop.getState());
}
}
@ -65,4 +62,3 @@ public class CreatureInteractLogging extends LoggingListener {
}
}
}

View File

@ -20,7 +20,7 @@ import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.util.LoggingUtil;
import de.diddiz.LogBlock.util.LoggingUtil;
public class DragonEggLogging extends LoggingListener {

View File

@ -1,24 +1,24 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.entity.Enderman;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class EndermenLogging extends LoggingListener {
public EndermenLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if (event.getEntity() instanceof Enderman && isLogging(event.getBlock().getWorld(), Logging.ENDERMEN)) {
consumer.queueBlockReplace(new Actor("Enderman"), event.getBlock().getState(), event.getBlockData()); // Figure out how to get the data of the placed block;
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.entity.Enderman;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class EndermenLogging extends LoggingListener {
public EndermenLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if (event.getEntity() instanceof Enderman && isLogging(event.getBlock().getWorld(), Logging.ENDERMEN)) {
consumer.queueBlockReplace(new Actor("Enderman"), event.getBlock().getState(), event.getBlockData()); // Figure out how to get the data of the placed block;
}
}
}

View File

@ -1,184 +1,228 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.util.BukkitUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.*;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.scheduler.BukkitRunnable;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese;
import static de.diddiz.util.BukkitUtils.getContainerBlocks;
import java.util.UUID;
public class ExplosionLogging extends LoggingListener {
private UUID lastBedInteractionPlayer;
private Location lastBedInteractionLocation;
public ExplosionLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld());
if (wcfg != null) {
Actor actor = new Actor("Explosion");
Entity source = event.getEntity();
if (source == null) {
if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
return;
}
} else if (source instanceof TNTPrimed) {
if (!wcfg.isLogging(Logging.TNTEXPLOSION)) {
return;
}
actor = new Actor("TNT");
} else if (source instanceof ExplosiveMinecart) {
if (!wcfg.isLogging(Logging.TNTMINECARTEXPLOSION)) {
return;
}
actor = new Actor("TNTMinecart");
} else if (source instanceof Creeper) {
if (!wcfg.isLogging(Logging.CREEPEREXPLOSION)) {
return;
}
if (logCreeperExplosionsAsPlayerWhoTriggeredThese) {
final Entity target = ((Creeper) source).getTarget();
actor = target instanceof Player ? Actor.actorFromEntity(target) : new Actor("Creeper");
} else {
new Actor("Creeper");
}
} else if (source instanceof Fireball) {
Fireball fireball = (Fireball) source;
ProjectileSource shooter = fireball.getShooter();
if (shooter == null) {
return;
}
if (shooter instanceof Ghast) {
if (!wcfg.isLogging(Logging.GHASTFIREBALLEXPLOSION)) {
return;
}
actor = Actor.actorFromProjectileSource(shooter);
} else if (shooter instanceof Wither) {
if (!wcfg.isLogging(Logging.WITHER)) {
return;
}
actor = Actor.actorFromProjectileSource(shooter);
}
} else if (source instanceof EnderDragon) {
if (!wcfg.isLogging(Logging.ENDERDRAGON)) {
return;
}
actor = Actor.actorFromEntity(source);
} else if (source instanceof Wither) {
if (!wcfg.isLogging(Logging.WITHER)) {
return;
}
actor = Actor.actorFromEntity(source);
} else if (source instanceof WitherSkull) {
if (!wcfg.isLogging(Logging.WITHER_SKULL)) {
return;
}
actor = Actor.actorFromEntity(source);
} else if (source instanceof EnderCrystal){
if (!wcfg.isLogging(Logging.ENDERCRYSTALEXPLOSION)) {
return;
}
actor = Actor.actorFromEntity(source);
} else {
if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
return;
}
}
for (final Block block : event.blockList()) {
final Material type = block.getType();
if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) {
consumer.queueSignBreak(actor, (Sign) block.getState());
} else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) {
consumer.queueContainerBreak(actor, block.getState());
} else {
consumer.queueBlockBreak(actor, block.getState());
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock() && BukkitUtils.isBed(event.getClickedBlock().getType())) {
Block block = event.getClickedBlock();
if (!Config.isLogging(block.getWorld(), Logging.BEDEXPLOSION)) {
return;
}
lastBedInteractionPlayer = event.getPlayer().getUniqueId();
lastBedInteractionLocation = block.getLocation();
new BukkitRunnable() {
@Override
public void run() {
lastBedInteractionPlayer = null;
lastBedInteractionLocation = null;
}
}.runTask(LogBlock.getInstance());
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockExplode(BlockExplodeEvent event) {
Player bedCause = null;
if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) {
Location block = event.getBlock().getLocation();
if (lastBedInteractionLocation.getWorld() == block.getWorld() && block.distanceSquared(lastBedInteractionLocation) <= 1) {
bedCause = Bukkit.getPlayer(lastBedInteractionPlayer);
}
}
for (final Block block : event.blockList()) {
final WorldConfig wcfg = getWorldConfig(block.getLocation().getWorld());
if (wcfg != null) {
Actor actor = new Actor("Explosion");
if (bedCause != null) {
if (!wcfg.isLogging(Logging.BEDEXPLOSION)) {
return;
}
if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) {
actor = Actor.actorFromEntity(bedCause);
}
} else if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
return;
}
final Material type = block.getType();
if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) {
consumer.queueSignBreak(actor, (Sign) block.getState());
} else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) {
consumer.queueContainerBreak(actor, block.getState());
} else {
consumer.queueBlockBreak(actor, block.getState());
}
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.LogBlock.util.BukkitUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.RespawnAnchor;
import org.bukkit.entity.*;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.scheduler.BukkitRunnable;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese;
import java.util.UUID;
public class ExplosionLogging extends LoggingListener {
private UUID lastBedInteractionPlayer;
private Location lastBedInteractionLocation;
private UUID lastRespawnAnchorInteractionPlayer;
private Location lastRespawnAnchorInteractionLocation;
public ExplosionLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld());
if (wcfg != null) {
Actor actor = new Actor("Explosion");
Entity source = event.getEntity();
if (source == null) {
if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
return;
}
} else if (source instanceof TNTPrimed) {
if (!wcfg.isLogging(Logging.TNTEXPLOSION)) {
return;
}
actor = new Actor("TNT");
} else if (source instanceof ExplosiveMinecart) {
if (!wcfg.isLogging(Logging.TNTMINECARTEXPLOSION)) {
return;
}
actor = new Actor("TNTMinecart");
} else if (source instanceof Creeper) {
if (!wcfg.isLogging(Logging.CREEPEREXPLOSION)) {
return;
}
if (logCreeperExplosionsAsPlayerWhoTriggeredThese) {
final Entity target = ((Creeper) source).getTarget();
actor = target instanceof Player ? Actor.actorFromEntity(target) : new Actor("Creeper");
} else {
actor = new Actor("Creeper");
}
} else if (source instanceof Wither) {
if (!wcfg.isLogging(Logging.WITHER)) {
return;
}
actor = Actor.actorFromEntity(source);
} else if (source instanceof WitherSkull) {
if (!wcfg.isLogging(Logging.WITHER_SKULL)) {
return;
}
actor = Actor.actorFromEntity(source);
} else if (source instanceof Fireball) {
Fireball fireball = (Fireball) source;
ProjectileSource shooter = fireball.getShooter();
if (shooter == null) {
if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
return;
}
actor = Actor.actorFromEntity(source);
} else if (shooter instanceof Ghast) {
if (!wcfg.isLogging(Logging.GHASTFIREBALLEXPLOSION)) {
return;
}
actor = Actor.actorFromProjectileSource(shooter);
} else if (shooter instanceof Wither) {
if (!wcfg.isLogging(Logging.WITHER)) {
return;
}
actor = Actor.actorFromProjectileSource(shooter);
}
} else if (source instanceof EnderDragon) {
if (!wcfg.isLogging(Logging.ENDERDRAGON)) {
return;
}
actor = Actor.actorFromEntity(source);
} else if (source instanceof EnderCrystal) {
if (!wcfg.isLogging(Logging.ENDERCRYSTALEXPLOSION)) {
return;
}
actor = Actor.actorFromEntity(source);
} else {
if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
return;
}
}
for (final Block block : event.blockList()) {
final Material type = block.getType();
if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.isContainerBlock(type) && !BukkitUtils.isShulkerBoxBlock(type)) {
consumer.queueContainerBreak(actor, block.getState());
} else {
consumer.queueBlockBreak(actor, block.getState());
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock()) {
Block block = event.getClickedBlock();
if (BukkitUtils.isBed(block.getType()) && !block.getWorld().isBedWorks()) {
if (!Config.isLogging(block.getWorld(), Logging.BEDEXPLOSION)) {
return;
}
lastBedInteractionPlayer = event.getPlayer().getUniqueId();
lastBedInteractionLocation = block.getLocation();
new BukkitRunnable() {
@Override
public void run() {
lastBedInteractionPlayer = null;
lastBedInteractionLocation = null;
}
}.runTask(LogBlock.getInstance());
} else if (block.getType() == Material.RESPAWN_ANCHOR && block.getBlockData() instanceof RespawnAnchor data) {
if (!Config.isLogging(block.getWorld(), Logging.RESPAWNANCHOREXPLOSION)) {
return;
}
ItemStack inHand = event.getItem();
int charges = data.getCharges();
if (charges < data.getMaximumCharges() && inHand != null && inHand.getType() == Material.GLOWSTONE) {
// charge
Actor actor = Actor.actorFromEntity(event.getPlayer());
RespawnAnchor blockNew = (RespawnAnchor) data.clone();
blockNew.setCharges(charges + 1);
consumer.queueBlockReplace(actor, block.getState(), blockNew);
} else if (charges > 0 && !block.getWorld().isRespawnAnchorWorks()) {
// explode
Actor actor = Actor.actorFromEntity(event.getPlayer());
consumer.queueBlockBreak(actor, block.getState());
lastRespawnAnchorInteractionPlayer = event.getPlayer().getUniqueId();
lastRespawnAnchorInteractionLocation = block.getLocation();
new BukkitRunnable() {
@Override
public void run() {
lastRespawnAnchorInteractionPlayer = null;
lastRespawnAnchorInteractionLocation = null;
}
}.runTask(LogBlock.getInstance());
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockExplode(BlockExplodeEvent event) {
Player bedCause = null;
if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) {
Location block = event.getBlock().getLocation();
if (lastBedInteractionLocation.getWorld() == block.getWorld() && block.distanceSquared(lastBedInteractionLocation) <= 1) {
bedCause = Bukkit.getPlayer(lastBedInteractionPlayer);
}
}
Player respawnAnchorCause = null;
if (lastRespawnAnchorInteractionPlayer != null && lastRespawnAnchorInteractionLocation != null) {
Location block = event.getBlock().getLocation();
if (lastRespawnAnchorInteractionLocation.equals(block)) {
respawnAnchorCause = Bukkit.getPlayer(lastRespawnAnchorInteractionPlayer);
}
}
for (final Block block : event.blockList()) {
final WorldConfig wcfg = getWorldConfig(block.getLocation().getWorld());
if (wcfg != null) {
Actor actor = new Actor("Explosion");
if (bedCause != null) {
if (!wcfg.isLogging(Logging.BEDEXPLOSION)) {
return;
}
if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) {
actor = Actor.actorFromEntity(bedCause);
} else {
actor = new Actor("BedExplosion");
}
} else if (respawnAnchorCause != null) {
if (!wcfg.isLogging(Logging.RESPAWNANCHOREXPLOSION)) {
return;
}
if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) {
actor = Actor.actorFromEntity(respawnAnchorCause);
} else {
actor = new Actor("RespawnAnchorExplosion");
}
} else if (!wcfg.isLogging(Logging.MISCEXPLOSION)) {
return;
}
final Material type = block.getType();
if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.isContainerBlock(type) && !BukkitUtils.isShulkerBoxBlock(type)) {
consumer.queueContainerBreak(actor, block.getState());
} else {
consumer.queueBlockBreak(actor, block.getState());
}
}
}
}
}

View File

@ -1,128 +1,127 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.util.BukkitUtils;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Levelled;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFormEvent;
import org.bukkit.event.block.BlockFromToEvent;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
public class FluidFlowLogging extends LoggingListener {
public FluidFlowLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockFromTo(BlockFromToEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) {
final BlockData blockDataFrom = event.getBlock().getBlockData();
Material typeFrom = blockDataFrom.getMaterial();
boolean fromWaterlogged = false;
if (blockDataFrom instanceof Waterlogged) {
typeFrom = Material.WATER;
fromWaterlogged = true;
}
if (typeFrom == Material.SEAGRASS || typeFrom == Material.KELP_PLANT || typeFrom == Material.KELP) {
typeFrom = Material.WATER;
fromWaterlogged = true;
}
Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null;
final Block to = event.getToBlock();
final Material typeTo = to.getType();
boolean down = event.getFace() == BlockFace.DOWN;
final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo);
if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) {
Levelled levelledFrom = (Levelled) blockDataFrom;
if (canFlow) {
if (isSurroundedByWater(to) && levelledFrom.getLevel() <= 2) {
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData());
} else {
Levelled newBlock = (Levelled) blockDataFrom.clone();
newBlock.setLevel(down ? 1 : levelledFrom.getLevel() + 1);
if (BukkitUtils.isEmpty(typeTo)) {
consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock);
} else {
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), newBlock);
}
}
} else if (typeTo == Material.WATER) {
if (down) {
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.STONE.createBlockData());
} else {
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData());
}
}
} else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) {
Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom;
Levelled newBlock = (Levelled) Material.WATER.createBlockData();
newBlock.setLevel(fromWaterlogged || down ? 1 : levelledFrom.getLevel() + 1);
if (BukkitUtils.isEmpty(typeTo)) {
consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock);
} else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), newBlock);
} else if (typeTo == Material.LAVA) {
int toLevel = ((Levelled) to.getBlockData()).getLevel();
if (toLevel == 0) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.OBSIDIAN.createBlockData());
} else if (event.getFace() == BlockFace.DOWN) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.STONE.createBlockData());
}
}
if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) {
for (final BlockFace face : new BlockFace[] { BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) {
final Block lower = to.getRelative(face);
if (lower.getType() == Material.LAVA) {
int toLevel = ((Levelled) lower.getBlockData()).getLevel();
if (toLevel == 0) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.OBSIDIAN.createBlockData());
} else if (event.getFace() == BlockFace.DOWN) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.STONE.createBlockData());
}
}
}
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockForm(BlockFormEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) {
if (wcfg.isLogging(Logging.LAVAFLOW) && event.getBlock().getType() == Material.WATER && event.getNewState().getType() == Material.COBBLESTONE) {
consumer.queueBlockReplace(new Actor("LavaFlow"), event.getBlock().getBlockData(), event.getNewState());
}
if (wcfg.isLogging(Logging.WATERFLOW) && event.getBlock().getType() == Material.LAVA) {
consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState());
}
if (wcfg.isLogging(Logging.WATERFLOW) && BukkitUtils.isConcreteBlock(event.getNewState().getType())) {
consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState());
}
}
}
private static boolean isSurroundedByWater(Block block) {
for (final BlockFace face : new BlockFace[] { BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) {
if (block.getRelative(face).getType() == Material.WATER) {
return true;
}
}
return false;
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.LogBlock.util.BukkitUtils;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Levelled;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFormEvent;
import org.bukkit.event.block.BlockFromToEvent;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
public class FluidFlowLogging extends LoggingListener {
public FluidFlowLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockFromTo(BlockFromToEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) {
final BlockData blockDataFrom = event.getBlock().getBlockData();
Material typeFrom = blockDataFrom.getMaterial();
boolean fromWaterlogged = false;
if (blockDataFrom instanceof Waterlogged) {
typeFrom = Material.WATER;
fromWaterlogged = true;
}
if (typeFrom == Material.SEAGRASS || typeFrom == Material.KELP_PLANT || typeFrom == Material.KELP) {
typeFrom = Material.WATER;
fromWaterlogged = true;
}
Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null;
final Block to = event.getToBlock();
final Material typeTo = to.getType();
boolean down = event.getFace() == BlockFace.DOWN;
final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.isNonFluidProofBlock(typeTo);
if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) {
Levelled levelledFrom = (Levelled) blockDataFrom;
if (canFlow) {
if (isSurroundedByWater(to) && levelledFrom.getLevel() <= 2) {
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData());
} else {
Levelled newBlock = (Levelled) blockDataFrom.clone();
newBlock.setLevel(down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel()));
if (BukkitUtils.isEmpty(typeTo)) {
consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock);
} else {
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), newBlock);
}
}
} else if (typeTo == Material.WATER) {
if (down) {
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.STONE.createBlockData());
} else {
consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData());
}
}
} else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) {
Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom;
Levelled newBlock = (Levelled) Material.WATER.createBlockData();
newBlock.setLevel(fromWaterlogged || down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel()));
if (BukkitUtils.isEmpty(typeTo)) {
consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock);
} else if (BukkitUtils.isNonFluidProofBlock(typeTo)) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), newBlock);
} else if (typeTo == Material.LAVA) {
int toLevel = ((Levelled) to.getBlockData()).getLevel();
if (toLevel == 0) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.OBSIDIAN.createBlockData());
} else if (event.getFace() == BlockFace.DOWN) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.STONE.createBlockData());
}
}
if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.isNonFluidProofBlock(typeTo)) {
for (final BlockFace face : new BlockFace[] { BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) {
final Block lower = to.getRelative(face);
if (lower.getType() == Material.LAVA) {
int toLevel = ((Levelled) lower.getBlockData()).getLevel();
if (toLevel == 0) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.OBSIDIAN.createBlockData());
} else if (event.getFace() == BlockFace.DOWN) {
consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.STONE.createBlockData());
}
}
}
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockForm(BlockFormEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) {
if (wcfg.isLogging(Logging.LAVAFLOW) && event.getBlock().getType() == Material.WATER && event.getNewState().getType() == Material.COBBLESTONE) {
consumer.queueBlockReplace(new Actor("LavaFlow"), event.getBlock().getBlockData(), event.getNewState());
}
if (wcfg.isLogging(Logging.WATERFLOW) && event.getBlock().getType() == Material.LAVA) {
consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState());
}
if (wcfg.isLogging(Logging.WATERFLOW) && BukkitUtils.isConcreteBlock(event.getNewState().getType())) {
consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState());
}
}
}
private static boolean isSurroundedByWater(Block block) {
for (final BlockFace face : new BlockFace[] { BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) {
if (block.getRelative(face).getType() == Material.WATER) {
return true;
}
}
return false;
}
}

View File

@ -1,201 +1,274 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.util.BukkitUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Note;
import org.bukkit.Note.Tone;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Openable;
import org.bukkit.block.data.type.Cake;
import org.bukkit.block.data.type.Comparator;
import org.bukkit.block.data.type.Comparator.Mode;
import org.bukkit.block.data.type.DaylightDetector;
import org.bukkit.block.data.type.Door;
import org.bukkit.block.data.type.NoteBlock;
import org.bukkit.block.data.type.Repeater;
import org.bukkit.block.data.type.Switch;
import org.bukkit.block.data.type.TurtleEgg;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
public class InteractLogging extends LoggingListener {
public InteractLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
if (wcfg != null) {
final Block clicked = event.getClickedBlock();
if (clicked == null) {
return;
}
final BlockData blockData = clicked.getBlockData();
final Material type = blockData.getMaterial();
final Player player = event.getPlayer();
final Location loc = clicked.getLocation();
switch (type) {
case OAK_FENCE_GATE:
case SPRUCE_FENCE_GATE:
case BIRCH_FENCE_GATE:
case JUNGLE_FENCE_GATE:
case ACACIA_FENCE_GATE:
case DARK_OAK_FENCE_GATE:
case OAK_TRAPDOOR:
case SPRUCE_TRAPDOOR:
case BIRCH_TRAPDOOR:
case JUNGLE_TRAPDOOR:
case ACACIA_TRAPDOOR:
case DARK_OAK_TRAPDOOR:
if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Openable newBlockData = (Openable) blockData.clone();
newBlockData.setOpen(!newBlockData.isOpen());
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
break;
case CAKE:
if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) {
Cake newBlockData = (Cake) blockData.clone();
if (newBlockData.getBites() < 6) {
newBlockData.setBites(newBlockData.getBites() + 1);
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
} else {
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData());
}
}
break;
case NOTE_BLOCK:
if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
NoteBlock newBlockData = (NoteBlock) blockData.clone();
if (newBlockData.getNote().getOctave() == 2) {
newBlockData.setNote(new Note(0, Tone.F, true));
} else {
newBlockData.setNote(newBlockData.getNote().sharped());
}
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
break;
case REPEATER:
if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Repeater newBlockData = (Repeater) blockData.clone();
newBlockData.setDelay((newBlockData.getDelay() % 4) + 1);
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
break;
case COMPARATOR:
if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Comparator newBlockData = (Comparator) blockData.clone();
newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE);
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
break;
case DAYLIGHT_DETECTOR:
if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
DaylightDetector newBlockData = (DaylightDetector) blockData.clone();
newBlockData.setInverted(!newBlockData.isInverted());
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
break;
case OAK_PRESSURE_PLATE:
case SPRUCE_PRESSURE_PLATE:
case BIRCH_PRESSURE_PLATE:
case JUNGLE_PRESSURE_PLATE:
case ACACIA_PRESSURE_PLATE:
case DARK_OAK_PRESSURE_PLATE:
case STONE_PRESSURE_PLATE:
case HEAVY_WEIGHTED_PRESSURE_PLATE:
case LIGHT_WEIGHTED_PRESSURE_PLATE:
if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) {
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
}
break;
case TRIPWIRE:
if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) {
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
}
break;
case FARMLAND:
if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) {
// 3 = Dirt ID
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData());
// Log the crop on top as being broken
Block trampledCrop = clicked.getRelative(BlockFace.UP);
if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) {
consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState());
}
}
break;
case TURTLE_EGG:
if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) {
TurtleEgg turtleEggData = (TurtleEgg) blockData;
int eggs = turtleEggData.getEggs();
if (eggs > 1) {
TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone();
turtleEggData2.setEggs(eggs - 1);
consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2);
} else {
consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData());
}
}
break;
case PUMPKIN:
if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
ItemStack inHand = event.getItem();
if (inHand != null && inHand.getType() == Material.SHEARS) {
BlockFace clickedFace = event.getBlockFace();
Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData();
if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) {
newBlockData.setFacing(clickedFace);
} else {
// use player distance to calculate the facing
Location playerLoc = player.getLocation();
playerLoc.subtract(0.5, 0, 0.5);
double dx = playerLoc.getX() - loc.getX();
double dz = playerLoc.getZ() - loc.getZ();
if (Math.abs(dx) > Math.abs(dz)) {
newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST);
} else {
newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH);
}
}
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
}
break;
default:
if (BukkitUtils.isButton(type) || type == Material.LEVER) {
if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Switch newBlockData = (Switch) blockData.clone();
if (!newBlockData.isPowered() || type == Material.LEVER) {
newBlockData.setPowered(!newBlockData.isPowered());
}
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
}
if (BukkitUtils.isWoodenDoor(type)) {
if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Door newBlockData = (Door) blockData.clone();
newBlockData.setOpen(!newBlockData.isOpen());
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
}
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.LogBlock.util.BukkitUtils;
import java.util.UUID;
import org.bukkit.DyeColor;
import org.bukkit.GameEvent;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Note;
import org.bukkit.Note.Tone;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Lightable;
import org.bukkit.block.data.Openable;
import org.bukkit.block.data.type.Cake;
import org.bukkit.block.data.type.Candle;
import org.bukkit.block.data.type.Comparator;
import org.bukkit.block.data.type.Comparator.Mode;
import org.bukkit.block.data.type.DaylightDetector;
import org.bukkit.block.data.type.Door;
import org.bukkit.block.data.type.NoteBlock;
import org.bukkit.block.data.type.Repeater;
import org.bukkit.block.data.type.Switch;
import org.bukkit.block.data.type.TurtleEgg;
import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide;
import org.bukkit.entity.Player;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.world.GenericGameEvent;
import org.bukkit.inventory.ItemStack;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
public class InteractLogging extends LoggingListener {
public InteractLogging(LogBlock lb) {
super(lb);
}
private UUID lastInteractionPlayer;
private BlockData lastInteractionBlockData;
private Location lastInteractionLocation;
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
if (wcfg != null) {
final Block clicked = event.getClickedBlock();
if (clicked == null) {
return;
}
final BlockData blockData = clicked.getBlockData();
final Material type = blockData.getMaterial();
final Player player = event.getPlayer();
final Location loc = clicked.getLocation();
lastInteractionPlayer = player.getUniqueId();
lastInteractionBlockData = blockData;
lastInteractionLocation = loc;
if (BukkitUtils.isFenceGate(type) || BukkitUtils.isWoodenTrapdoor(type)) {
if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Openable newBlockData = (Openable) blockData.clone();
newBlockData.setOpen(!newBlockData.isOpen());
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
} else if (BukkitUtils.isPressurePlate(type)) {
if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) {
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
}
} else if (BukkitUtils.isWoodenDoor(type)) {
if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Door newBlockData = (Door) blockData.clone();
newBlockData.setOpen(!newBlockData.isOpen());
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
} else if (BukkitUtils.isButton(type) || type == Material.LEVER) {
if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Switch newBlockData = (Switch) blockData.clone();
if (!newBlockData.isPowered() || type == Material.LEVER) {
newBlockData.setPowered(!newBlockData.isPowered());
}
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
} else if (BukkitUtils.isSign(type)) {
if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null) {
Material itemType = event.getItem().getType();
if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC || itemType == Material.HONEYCOMB) {
final BlockState before = event.getClickedBlock().getState();
if (before instanceof Sign signBefore) {
if (!signBefore.isWaxed()) {
final Sign signAfter = (Sign) event.getClickedBlock().getState();
Side side = BukkitUtils.getFacingSignSide(player, clicked);
SignSide signSideBefore = signBefore.getSide(side);
SignSide signSideAfter = signAfter.getSide(side);
if (itemType == Material.GLOW_INK_SAC) {
if (!signSideBefore.isGlowingText() && hasText(signSideBefore)) {
signSideAfter.setGlowingText(true);
consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter);
}
} else if (itemType == Material.INK_SAC) {
if (signSideBefore.isGlowingText() && hasText(signSideBefore)) {
signSideAfter.setGlowingText(false);
consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter);
}
} else if (itemType == Material.HONEYCOMB) {
signAfter.setWaxed(true);
consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter);
} else if (BukkitUtils.isDye(itemType) && hasText(signSideBefore)) {
DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType);
if (newColor != null && signSideBefore.getColor() != newColor) {
signSideAfter.setColor(newColor);
consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter);
}
}
}
}
}
}
} else if (type == Material.CAKE) {
if (event.hasItem() && BukkitUtils.isCandle(event.getItem().getType()) && event.useItemInHand() != Result.DENY) {
BlockData newBlockData = Material.valueOf(event.getItem().getType().name() + "_CAKE").createBlockData();
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
} else if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) {
Cake newBlockData = (Cake) blockData.clone();
if (newBlockData.getBites() < 6) {
newBlockData.setBites(newBlockData.getBites() + 1);
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
} else {
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData());
}
}
} else if (type == Material.NOTE_BLOCK) {
if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
NoteBlock newBlockData = (NoteBlock) blockData.clone();
if (newBlockData.getNote().getOctave() == 2) {
newBlockData.setNote(new Note(0, Tone.F, true));
} else {
newBlockData.setNote(newBlockData.getNote().sharped());
}
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
} else if (type == Material.REPEATER) {
if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Repeater newBlockData = (Repeater) blockData.clone();
newBlockData.setDelay((newBlockData.getDelay() % 4) + 1);
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
} else if (type == Material.COMPARATOR) {
if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Comparator newBlockData = (Comparator) blockData.clone();
newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE);
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
} else if (type == Material.DAYLIGHT_DETECTOR) {
if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
DaylightDetector newBlockData = (DaylightDetector) blockData.clone();
newBlockData.setInverted(!newBlockData.isInverted());
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
} else if (type == Material.TRIPWIRE) {
if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) {
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData);
}
} else if (type == Material.FARMLAND) {
if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) {
// 3 = Dirt ID
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData());
// Log the crop on top as being broken
Block trampledCrop = clicked.getRelative(BlockFace.UP);
if (BukkitUtils.isCropBlock(trampledCrop.getType())) {
consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState());
}
}
} else if (type == Material.TURTLE_EGG) {
if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) {
TurtleEgg turtleEggData = (TurtleEgg) blockData;
int eggs = turtleEggData.getEggs();
if (eggs > 1) {
TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone();
turtleEggData2.setEggs(eggs - 1);
consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2);
} else {
consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData());
}
}
} else if (type == Material.PUMPKIN) {
if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
ItemStack inHand = event.getItem();
if (inHand != null && inHand.getType() == Material.SHEARS) {
BlockFace clickedFace = event.getBlockFace();
Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData();
if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) {
newBlockData.setFacing(clickedFace);
} else {
// use player distance to calculate the facing
Location playerLoc = player.getLocation();
playerLoc.subtract(0.5, 0, 0.5);
double dx = playerLoc.getX() - loc.getX();
double dz = playerLoc.getZ() - loc.getZ();
if (Math.abs(dx) > Math.abs(dz)) {
newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST);
} else {
newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH);
}
}
consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData);
}
}
}
}
}
private boolean hasText(SignSide signSide) {
for (int i = 0; i < 4; i++) {
if (!signSide.getLine(i).isEmpty()) {
return true;
}
}
return false;
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onGenericGameEvent(GenericGameEvent event) {
if (lastInteractionPlayer != null && event.getEntity() != null && event.getEntity().getUniqueId().equals(lastInteractionPlayer) && lastInteractionLocation != null && event.getLocation().equals(lastInteractionLocation)) {
if (lastInteractionBlockData instanceof Candle) {
Candle previousCandle = (Candle) lastInteractionBlockData;
if (previousCandle.isLit()) {
BlockData newData = lastInteractionLocation.getBlock().getBlockData();
if (newData instanceof Candle) {
Candle newCandle = (Candle) newData;
if (!newCandle.isLit() && !newCandle.isWaterlogged()) {
// log candle extinguish
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData);
}
}
}
} else if (lastInteractionBlockData instanceof Lightable && BukkitUtils.isCandleCake(lastInteractionBlockData.getMaterial())) {
Lightable previousLightable = (Lightable) lastInteractionBlockData;
BlockData newData = lastInteractionLocation.getBlock().getBlockData();
if (event.getEvent().equals(GameEvent.EAT)) {
final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld());
if (wcfg.isLogging(Logging.CAKEEAT)) {
// nom nom (don't know why newData is incorrect here)
newData = Material.CAKE.createBlockData();
((Cake) newData).setBites(1);
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData);
}
} else if (previousLightable.isLit()) {
if (newData instanceof Lightable) {
Lightable newLightable = (Lightable) newData;
if (!newLightable.isLit()) {
// log cake extinguish
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData);
}
}
}
}
}
lastInteractionPlayer = null;
lastInteractionBlockData = null;
lastInteractionLocation = null;
}
}

View File

@ -1,50 +1,51 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import static de.diddiz.LogBlock.config.Config.*;
public class KillLogging extends LoggingListener {
public KillLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent deathEvent) {
EntityDamageEvent event = deathEvent.getEntity().getLastDamageCause();
// For a death event, there should always be a damage event and it should not be cancelled. Check anyway.
if (event != null && event.isCancelled() == false && isLogging(event.getEntity().getWorld(), Logging.KILL) && event.getEntity() instanceof LivingEntity) {
final LivingEntity victim = (LivingEntity) event.getEntity();
if (event instanceof EntityDamageByEntityEvent) {
final Entity killer = ((EntityDamageByEntityEvent) event).getDamager();
if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player)) {
return;
} else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) {
return;
}
consumer.queueKill(killer, victim);
} else if (logEnvironmentalKills) {
if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player)) {
return;
} else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster))) {
return;
}
consumer.queueKill(new Actor(event.getCause().toString()), victim);
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import static de.diddiz.LogBlock.config.Config.*;
public class KillLogging extends LoggingListener {
public KillLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent deathEvent) {
EntityDamageEvent event = deathEvent.getEntity().getLastDamageCause();
// For a death event, there should always be a damage event and it should not be cancelled. Check anyway.
if (event != null && event.isCancelled() == false && isLogging(event.getEntity().getWorld(), Logging.KILL) && event.getEntity() instanceof LivingEntity) {
final LivingEntity victim = (LivingEntity) event.getEntity();
if (event instanceof EntityDamageByEntityEvent) {
final Entity killer = ((EntityDamageByEntityEvent) event).getDamager();
if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player)) {
return;
} else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) {
return;
}
consumer.queueKill(killer, victim);
} else if (deathEvent.getEntity().getKiller() != null) {
consumer.queueKill(deathEvent.getEntity().getKiller(), victim);
} else if (logEnvironmentalKills) {
if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player)) {
return;
} else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster))) {
return;
}
consumer.queueKill(new Actor(event.getCause().toString()), victim);
}
}
}
}

View File

@ -1,26 +1,26 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.LeavesDecayEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.util.LoggingUtil.smartLogBlockBreak;
import static de.diddiz.util.LoggingUtil.smartLogFallables;
public class LeavesDecayLogging extends LoggingListener {
public LeavesDecayLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onLeavesDecay(LeavesDecayEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.LEAVESDECAY)) {
smartLogBlockBreak(consumer, new Actor("LeavesDecay"), event.getBlock());
smartLogFallables(consumer, new Actor("LeavesDecay"), event.getBlock());
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.LeavesDecayEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables;
public class LeavesDecayLogging extends LoggingListener {
public LeavesDecayLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onLeavesDecay(LeavesDecayEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.LEAVESDECAY)) {
smartLogBlockBreak(consumer, new Actor("LeavesDecay"), event.getBlock());
smartLogFallables(consumer, new Actor("LeavesDecay"), event.getBlock());
}
}
}

View File

@ -0,0 +1,67 @@
package de.diddiz.LogBlock.listeners;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.Lectern;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerTakeLecternBookEvent;
import org.bukkit.inventory.ItemStack;
public class LecternLogging extends LoggingListener {
public LecternLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
if (wcfg != null && wcfg.isLogging(Logging.LECTERNBOOKCHANGE)) {
final BlockState before = event.getBlockReplacedState();
final BlockState after = event.getBlockPlaced().getState();
if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) {
Lectern lecternBefore = (Lectern) before.getBlock().getState();
ItemStack book = lecternBefore.getSnapshotInventory().getItem(0);
try {
lecternBefore.getSnapshotInventory().setItem(0, null);
} catch (NullPointerException e) {
//ignored
}
lecternBefore.setBlockData(before.getBlockData());
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), lecternBefore, after);
try {
lecternBefore.getSnapshotInventory().setItem(0, book);
} catch (NullPointerException e) {
//ignored
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
if (wcfg != null && wcfg.isLogging(Logging.LECTERNBOOKCHANGE)) {
Lectern oldState = event.getLectern();
Lectern newState = (Lectern) oldState.getBlock().getState();
try {
newState.getSnapshotInventory().setItem(0, null);
} catch (NullPointerException e) {
//ignored
}
org.bukkit.block.data.type.Lectern oldBlockData = (org.bukkit.block.data.type.Lectern) oldState.getBlockData();
org.bukkit.block.data.type.Lectern blockData = (org.bukkit.block.data.type.Lectern) Material.LECTERN.createBlockData();
blockData.setFacing(oldBlockData.getFacing());
blockData.setPowered(oldBlockData.isPowered());
newState.setBlockData(blockData);
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), oldState, newState);
}
}
}

View File

@ -1,13 +1,13 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Consumer;
import de.diddiz.LogBlock.LogBlock;
import org.bukkit.event.Listener;
public class LoggingListener implements Listener {
protected final Consumer consumer;
public LoggingListener(LogBlock lb) {
consumer = lb.getConsumer();
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Consumer;
import de.diddiz.LogBlock.LogBlock;
import org.bukkit.event.Listener;
public class LoggingListener implements Listener {
protected final Consumer consumer;
public LoggingListener(LogBlock lb) {
consumer = lb.getConsumer();
}
}

View File

@ -0,0 +1,28 @@
package de.diddiz.LogBlock.listeners;
import static de.diddiz.LogBlock.config.Config.isLogging;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFormEvent;
public class OxidizationLogging extends LoggingListener {
public OxidizationLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPhysics(BlockFormEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.OXIDIZATION)) {
final Material type = event.getNewState().getType();
if (type.name().contains("COPPER")) {
consumer.queueBlockReplace(new Actor("NaturalOxidization"), event.getBlock().getState(), event.getNewState());
}
}
}
}

View File

@ -1,43 +1,43 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.config.Config;
import java.util.HashMap;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
public class PlayerInfoLogging extends LoggingListener {
private final HashMap<UUID, Long> playerLogins = new HashMap<>();
public PlayerInfoLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(PlayerJoinEvent event) {
playerLogins.put(event.getPlayer().getUniqueId(), System.currentTimeMillis());
consumer.queueJoin(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
onPlayerQuit(event.getPlayer());
}
public void onPlayerQuit(Player player) {
Long joinTime = playerLogins.remove(player.getUniqueId());
if (Config.logPlayerInfo && joinTime != null) {
long onlineTime = (System.currentTimeMillis() - joinTime) / 1000;
if (onlineTime > 0) {
consumer.queueLeave(player, onlineTime);
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.config.Config;
import java.util.HashMap;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
public class PlayerInfoLogging extends LoggingListener {
private final HashMap<UUID, Long> playerLogins = new HashMap<>();
public PlayerInfoLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(PlayerJoinEvent event) {
playerLogins.put(event.getPlayer().getUniqueId(), System.currentTimeMillis());
consumer.queueJoin(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
onPlayerQuit(event.getPlayer());
}
public void onPlayerQuit(Player player) {
Long joinTime = playerLogins.remove(player.getUniqueId());
if (Config.logPlayerInfo && joinTime != null) {
long onlineTime = (System.currentTimeMillis() - joinTime) / 1000;
if (onlineTime > 0) {
consumer.queueLeave(player, onlineTime);
}
}
}
}

View File

@ -0,0 +1,171 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import java.util.ArrayDeque;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockFadeEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables;
public class ScaffoldingLogging extends LoggingListener {
private final static long MAX_SCAFFOLDING_LOG_TIME_MS = 2000;
private final static EnumSet<BlockFace> NEIGHBOURS_SIDES_AND_UP = EnumSet.of(BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
private final static EnumSet<BlockFace> NEIGHBOURS_SIDES_AND_BELOW = EnumSet.of(BlockFace.DOWN, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
private final ArrayDeque<ScaffoldingBreaker> scaffoldingBreakersList = new ArrayDeque<>();
private final HashMap<Location, ScaffoldingBreaker> scaffoldingBreakersByLocation = new HashMap<>();
private final HashMap<Location, Actor> scaffoldingPlacersByLocation = new HashMap<>();
public ScaffoldingLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockFade(BlockFadeEvent event) {
Block block = event.getBlock();
if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) {
final Material type = block.getType();
if (type == Material.SCAFFOLDING) {
Actor actor = scaffoldingPlacersByLocation.get(block.getLocation()); // get placer before cleanupScaffoldingBreakers
cleanupScaffoldingBreakers();
if (actor == null) {
actor = getScaffoldingBreaker(block);
if (actor != null) {
for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) {
Block otherBlock = block.getRelative(dir);
if (otherBlock.getType() == Material.SCAFFOLDING) {
addScaffoldingBreaker(actor, otherBlock);
}
}
} else {
actor = new Actor("ScaffoldingFall");
}
}
consumer.queueBlockReplace(actor, block.getState(), event.getNewState());
smartLogFallables(consumer, actor, block);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event) {
Block block = event.getBlock();
if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) {
cleanupScaffoldingBreakers();
Block otherBlock;
if (block.getType() == Material.SCAFFOLDING) {
for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) {
otherBlock = block.getRelative(dir);
if (otherBlock.getType() == Material.SCAFFOLDING) {
addScaffoldingBreaker(Actor.actorFromEntity(event.getPlayer()), otherBlock);
}
}
} else if ((otherBlock = block.getRelative(BlockFace.UP)).getType() == Material.SCAFFOLDING) {
addScaffoldingBreaker(Actor.actorFromEntity(event.getPlayer()), otherBlock);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent event) {
Block block = event.getBlock();
if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) {
cleanupScaffoldingBreakers();
if (block.getType() == Material.SCAFFOLDING) {
scaffoldingPlacersByLocation.put(block.getLocation(), Actor.actorFromEntity(event.getPlayer()));
}
}
}
public void addScaffoldingBreaker(Actor actor, Block block) {
ScaffoldingBreaker breaker = new ScaffoldingBreaker(actor, block.getLocation());
scaffoldingBreakersList.addLast(breaker);
scaffoldingBreakersByLocation.put(breaker.getLocation(), breaker);
}
private void cleanupScaffoldingBreakers() {
if (!scaffoldingPlacersByLocation.isEmpty()) {
scaffoldingPlacersByLocation.clear();
}
if (!scaffoldingBreakersList.isEmpty()) {
long time = System.currentTimeMillis() - MAX_SCAFFOLDING_LOG_TIME_MS;
while (!scaffoldingBreakersList.isEmpty() && scaffoldingBreakersList.getFirst().getTime() < time) {
ScaffoldingBreaker breaker = scaffoldingBreakersList.removeFirst();
scaffoldingBreakersByLocation.remove(breaker.getLocation(), breaker);
}
}
}
private Actor getScaffoldingBreaker(Block block) {
if (scaffoldingBreakersList.isEmpty()) {
return null;
}
ScaffoldingBreaker breaker = scaffoldingBreakersByLocation.get(block.getLocation());
if (breaker != null) {
return breaker.getActor();
}
// Search all connected scaffoldings
ArrayDeque<Block> front = new ArrayDeque<>();
HashSet<Block> frontAndDone = new HashSet<>();
front.addLast(block);
frontAndDone.add(block);
while (!front.isEmpty()) {
Block current = front.removeFirst();
Location loc = current.getLocation();
breaker = scaffoldingBreakersByLocation.get(loc);
if (breaker != null) {
return breaker.getActor();
}
for (BlockFace dir : NEIGHBOURS_SIDES_AND_BELOW) {
Block otherBlock = current.getRelative(dir);
if (!frontAndDone.contains(otherBlock) && otherBlock.getType() == Material.SCAFFOLDING) {
front.addLast(otherBlock);
frontAndDone.add(otherBlock);
}
}
}
return null;
}
class ScaffoldingBreaker {
protected final Actor actor;
protected final long time;
protected final Location location;
public ScaffoldingBreaker(Actor actor, Location location) {
this.actor = actor;
this.location = location;
this.time = System.currentTimeMillis();
}
public Actor getActor() {
return actor;
}
public Location getLocation() {
return location;
}
public long getTime() {
return time;
}
}
}

View File

@ -1,23 +1,40 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.SignChangeEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class SignChangeLogging extends LoggingListener {
public SignChangeLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSignChange(SignChangeEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) {
consumer.queueSignPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getBlockData(), event.getLines());
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import java.util.Objects;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.SignSide;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.SignChangeEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class SignChangeLogging extends LoggingListener {
public SignChangeLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSignChange(SignChangeEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) {
BlockState newState = event.getBlock().getState();
if (newState instanceof Sign sign) {
SignSide signSide = sign.getSide(event.getSide());
boolean changed = false;
for (int i = 0; i < 4; i++) {
if (!Objects.equals(signSide.getLine(i), event.getLine(i))) {
signSide.setLine(i, event.getLine(i));
changed = true;
}
}
if (changed) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getState(), newState);
}
}
}
}
}

View File

@ -1,28 +1,28 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFadeEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class SnowFadeLogging extends LoggingListener {
public SnowFadeLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockFade(BlockFadeEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.SNOWFADE)) {
final Material type = event.getBlock().getType();
if (type == Material.SNOW || type == Material.ICE) {
consumer.queueBlockReplace(new Actor("SnowFade"), event.getBlock().getState(), event.getNewState());
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFadeEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class SnowFadeLogging extends LoggingListener {
public SnowFadeLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockFade(BlockFadeEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.SNOWFADE)) {
final Material type = event.getBlock().getType();
if (type == Material.SNOW || type == Material.ICE) {
consumer.queueBlockReplace(new Actor("SnowFade"), event.getBlock().getState(), event.getNewState());
}
}
}
}

View File

@ -1,34 +1,28 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFormEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class SnowFormLogging extends LoggingListener {
public SnowFormLogging(LogBlock lb) {
super(lb);
}
// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
// public void onLeavesDecay(LeavesDecayEvent event) {
// if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM))
// consumer.queueBlockBreak("LeavesDecay", event.getBlock().getState());
// }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockForm(BlockFormEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) {
final Material type = event.getNewState().getType();
if (type == Material.SNOW || type == Material.ICE) {
consumer.queueBlockReplace(new Actor("SnowForm"), event.getBlock().getState(), event.getNewState());
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFormEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class SnowFormLogging extends LoggingListener {
public SnowFormLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockForm(BlockFormEvent event) {
if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) {
final Material type = event.getNewState().getType();
if (type == Material.SNOW || type == Material.ICE) {
consumer.queueBlockReplace(new Actor("SnowForm"), event.getBlock().getState(), event.getNewState());
}
}
}
}

View File

@ -1,40 +1,34 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import org.bukkit.block.BlockState;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.world.StructureGrowEvent;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
public class StructureGrowLogging extends LoggingListener {
public StructureGrowLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onStructureGrow(StructureGrowEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getWorld());
if (wcfg != null) {
final Actor actor;
if (event.getPlayer() != null) {
if (!wcfg.isLogging(Logging.BONEMEALSTRUCTUREGROW)) {
return;
}
actor = Actor.actorFromEntity(event.getPlayer());
} else {
if (!wcfg.isLogging(Logging.NATURALSTRUCTUREGROW)) {
return;
}
actor = new Actor("NaturalGrow");
}
for (final BlockState state : event.getBlocks()) {
consumer.queueBlockReplace(actor, state.getBlock().getState(), state);
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import org.bukkit.block.BlockState;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.world.StructureGrowEvent;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
public class StructureGrowLogging extends LoggingListener {
public StructureGrowLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onStructureGrow(StructureGrowEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getWorld());
if (wcfg != null) {
if (!wcfg.isLogging(Logging.NATURALSTRUCTUREGROW)) {
return;
}
if (!event.isFromBonemeal()) {
final Actor actor = new Actor("NaturalGrow");
for (final BlockState state : event.getBlocks()) {
consumer.queueBlockReplace(actor, state.getBlock().getState(), state);
}
}
}
}
}

View File

@ -1,142 +1,151 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.*;
import de.diddiz.util.BukkitUtils;
import de.diddiz.worldedit.CuboidRegion;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import java.util.Map.Entry;
import static de.diddiz.LogBlock.Session.getSession;
import static de.diddiz.LogBlock.Session.hasSession;
import static de.diddiz.LogBlock.config.Config.isLogged;
import static de.diddiz.LogBlock.config.Config.toolsByType;
public class ToolListener implements Listener {
private final CommandsHandler handler;
private final LogBlock logblock;
public ToolListener(LogBlock logblock) {
this.logblock = logblock;
handler = logblock.getCommandsHandler();
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getMaterial() != null) {
final Action action = event.getAction();
final Material type = event.getMaterial();
final Tool tool = toolsByType.get(type);
final Player player = event.getPlayer();
if (tool != null && (action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) && logblock.hasPermission(player, "logblock.tools." + tool.name)) {
final ToolBehavior behavior = action == Action.RIGHT_CLICK_BLOCK ? tool.rightClickBehavior : tool.leftClickBehavior;
final ToolData toolData = getSession(player).toolData.get(tool);
if (behavior != ToolBehavior.NONE && toolData.enabled) {
if (!isLogged(player.getWorld())) {
player.sendMessage(ChatColor.RED + "This world is not currently logged.");
event.setCancelled(true);
return;
}
final Block block = event.getClickedBlock();
final QueryParams params = toolData.params.clone();
params.loc = null;
params.sel = null;
if (behavior == ToolBehavior.BLOCK) {
params.setLocation(block.getRelative(event.getBlockFace()).getLocation());
} else if (tool.params.radius != 0) {
params.setLocation(block.getLocation());
} else {
Block otherHalfChest = BukkitUtils.getConnectedChest(block);
if (otherHalfChest == null) {
params.setLocation(block.getLocation());
} else {
params.setSelection(CuboidRegion.fromCorners(block.getLocation().getWorld(), block.getLocation(), otherHalfChest.getLocation()));
}
}
try {
params.validate();
if (toolData.mode == ToolMode.ROLLBACK) {
handler.new CommandRollback(player, params, true);
} else if (toolData.mode == ToolMode.REDO) {
handler.new CommandRedo(player, params, true);
} else if (toolData.mode == ToolMode.CLEARLOG) {
handler.new CommandClearLog(player, params, true);
} else if (toolData.mode == ToolMode.WRITELOGFILE) {
handler.new CommandWriteLogFile(player, params, true);
} else {
handler.new CommandLookup(player, params, true);
}
} catch (final Exception ex) {
player.sendMessage(ChatColor.RED + ex.getMessage());
}
event.setCancelled(true);
}
}
}
}
@EventHandler
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
final Player player = event.getPlayer();
if (hasSession(player)) {
final Session session = getSession(player);
for (final Entry<Tool, ToolData> entry : session.toolData.entrySet()) {
final Tool tool = entry.getKey();
final ToolData toolData = entry.getValue();
if (toolData.enabled && !logblock.hasPermission(player, "logblock.tools." + tool.name)) {
toolData.enabled = false;
if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) {
player.getInventory().removeItem(new ItemStack(tool.item, 1));
}
player.sendMessage(ChatColor.GREEN + "Tool disabled.");
}
}
}
}
@EventHandler
public void onPlayerDropItem(PlayerDropItemEvent event) {
final Player player = event.getPlayer();
if (hasSession(player)) {
final Session session = getSession(player);
for (final Entry<Tool, ToolData> entry : session.toolData.entrySet()) {
final Tool tool = entry.getKey();
final ToolData toolData = entry.getValue();
final Material item = event.getItemDrop().getItemStack().getType();
if (item == tool.item && toolData.enabled) {
if (tool.dropToDisable) {
toolData.enabled = false;
ItemStack stack = event.getItemDrop().getItemStack();
if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) {
if (stack.isSimilar(new ItemStack(item))) {
if (stack.getAmount() > 1) {
stack.setAmount(stack.getAmount() - 1);
event.getItemDrop().setItemStack(stack);
} else {
event.getItemDrop().remove();
}
}
}
if (BukkitUtils.hasInventoryStorageSpaceFor(player.getInventory(), stack)) {
event.setCancelled(true);
}
player.sendMessage(ChatColor.GREEN + "Tool disabled.");
} else if (!tool.canDrop) {
player.sendMessage(ChatColor.RED + "You cannot drop this tool.");
event.setCancelled(true);
}
}
}
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.*;
import de.diddiz.LogBlock.events.ToolUseEvent;
import de.diddiz.LogBlock.util.BukkitUtils;
import de.diddiz.LogBlock.util.CuboidRegion;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import java.util.Map.Entry;
import static de.diddiz.LogBlock.Session.getSession;
import static de.diddiz.LogBlock.Session.hasSession;
import static de.diddiz.LogBlock.config.Config.isLogged;
import static de.diddiz.LogBlock.config.Config.toolsByType;
public class ToolListener implements Listener {
private final CommandsHandler handler;
private final LogBlock logblock;
public ToolListener(LogBlock logblock) {
this.logblock = logblock;
handler = logblock.getCommandsHandler();
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getMaterial() != null) {
final Action action = event.getAction();
final Material type = event.getMaterial();
final Tool tool = toolsByType.get(type);
final Player player = event.getPlayer();
if (tool != null && (action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) && logblock.hasPermission(player, "logblock.tools." + tool.name)) {
final ToolBehavior behavior = action == Action.RIGHT_CLICK_BLOCK ? tool.rightClickBehavior : tool.leftClickBehavior;
final ToolData toolData = getSession(player).toolData.get(tool);
if (behavior != ToolBehavior.NONE && toolData.enabled) {
if (!isLogged(player.getWorld())) {
player.sendMessage(ChatColor.RED + "This world is not currently logged.");
event.setCancelled(true);
return;
}
final Block block = event.getClickedBlock();
final QueryParams params = toolData.params.clone();
params.loc = null;
params.sel = null;
if (behavior == ToolBehavior.BLOCK) {
params.setLocation(block.getRelative(event.getBlockFace()).getLocation());
} else if (tool.params.radius != 0) {
params.setLocation(block.getLocation());
} else {
Block otherHalfChest = BukkitUtils.getConnectedChest(block);
if (otherHalfChest == null) {
params.setLocation(block.getLocation());
} else {
params.setSelection(CuboidRegion.fromCorners(block.getLocation().getWorld(), block.getLocation(), otherHalfChest.getLocation()));
}
}
try {
params.validate();
if (this.callToolUseEvent(new ToolUseEvent(player, tool, behavior, params))) {
return;
}
if (toolData.mode == ToolMode.ROLLBACK) {
handler.new CommandRollback(player, params, true);
} else if (toolData.mode == ToolMode.REDO) {
handler.new CommandRedo(player, params, true);
} else if (toolData.mode == ToolMode.CLEARLOG) {
handler.new CommandClearLog(player, params, true);
} else if (toolData.mode == ToolMode.WRITELOGFILE) {
handler.new CommandWriteLogFile(player, params, true);
} else {
handler.new CommandLookup(player, params, true);
}
} catch (final Exception ex) {
player.sendMessage(ChatColor.RED + ex.getMessage());
}
event.setCancelled(true);
}
}
}
}
private boolean callToolUseEvent(ToolUseEvent event) {
this.logblock.getServer().getPluginManager().callEvent(event);
return event.isCancelled();
}
@EventHandler
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
final Player player = event.getPlayer();
if (hasSession(player)) {
final Session session = getSession(player);
for (final Entry<Tool, ToolData> entry : session.toolData.entrySet()) {
final Tool tool = entry.getKey();
final ToolData toolData = entry.getValue();
if (toolData.enabled && !logblock.hasPermission(player, "logblock.tools." + tool.name)) {
toolData.enabled = false;
if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) {
player.getInventory().removeItem(new ItemStack(tool.item, 1));
}
player.sendMessage(ChatColor.GREEN + "Tool disabled.");
}
}
}
}
@EventHandler
public void onPlayerDropItem(PlayerDropItemEvent event) {
final Player player = event.getPlayer();
if (hasSession(player)) {
final Session session = getSession(player);
for (final Entry<Tool, ToolData> entry : session.toolData.entrySet()) {
final Tool tool = entry.getKey();
final ToolData toolData = entry.getValue();
final Material item = event.getItemDrop().getItemStack().getType();
if (item == tool.item && toolData.enabled) {
if (tool.dropToDisable) {
toolData.enabled = false;
ItemStack stack = event.getItemDrop().getItemStack();
if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) {
if (stack.isSimilar(new ItemStack(item))) {
if (stack.getAmount() > 1) {
stack.setAmount(stack.getAmount() - 1);
event.getItemDrop().setItemStack(stack);
} else {
event.getItemDrop().remove();
}
}
}
if (BukkitUtils.hasInventoryStorageSpaceFor(player.getInventory(), stack)) {
event.setCancelled(true);
}
player.sendMessage(ChatColor.GREEN + "Tool disabled.");
} else if (!tool.canDrop) {
player.sendMessage(ChatColor.RED + "You cannot drop this tool.");
event.setCancelled(true);
}
}
}
}
}
}

View File

@ -1,24 +1,24 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.entity.Wither;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class WitherLogging extends LoggingListener {
public WitherLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if (event.getEntity() instanceof Wither && isLogging(event.getBlock().getWorld(), Logging.WITHER)) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getBlockData()); // Wither walked through a block.
}
}
}
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.entity.Wither;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class WitherLogging extends LoggingListener {
public WitherLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if (event.getEntity() instanceof Wither && isLogging(event.getBlock().getWorld(), Logging.WITHER)) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getBlockData()); // Wither walked through a block.
}
}
}

View File

@ -15,7 +15,7 @@ import de.diddiz.LogBlock.LogBlock;
public class Questioner {
private final LogBlock logBlock;
private final ConcurrentHashMap<UUID, Question> questions = new ConcurrentHashMap<UUID, Question>();
private final ConcurrentHashMap<UUID, Question> questions = new ConcurrentHashMap<>();
public Questioner(LogBlock logBlock) {
this.logBlock = logBlock;
@ -42,6 +42,7 @@ public class Questioner {
}
private class QuestionsReaper implements Runnable {
@Override
public void run() {
if (questions.isEmpty()) {
return;

View File

@ -0,0 +1,24 @@
package de.diddiz.LogBlock.util;
import net.md_5.bungee.api.ChatColor;
public enum ActionColor {
DESTROY(ChatColor.RED),
CREATE(ChatColor.DARK_GREEN),
INTERACT(ChatColor.GRAY);
private final ChatColor color;
ActionColor(ChatColor color) {
this.color = color;
}
public ChatColor getColor() {
return color;
}
@Override
public String toString() {
return color.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,473 +1,424 @@
package de.diddiz.util;
// Taken from maven-artifact at
// http://grepcode.com/file_/repo1.maven.org/maven2/org.apache.maven/maven-artifact/3.2.3/org/apache/maven/artifact/versioning/ComparableVersion.java/?v=source
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Properties;
import java.util.Stack;
/**
* Generic implementation of version comparison.
*
* <p>Features:
* <ul>
* <li>mixing of '<code>-</code>' (dash) and '<code>.</code>' (dot) separators,</li>
* <li>transition between characters and digits also constitutes a separator:
* <code>1.0alpha1 =&gt; [1, 0, alpha, 1]</code></li>
* <li>unlimited number of version components,</li>
* <li>version components in the text can be digits or strings,</li>
* <li>strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering.
* Well-known qualifiers (case insensitive) are:<ul>
* <li><code>alpha</code> or <code>a</code></li>
* <li><code>beta</code> or <code>b</code></li>
* <li><code>milestone</code> or <code>m</code></li>
* <li><code>rc</code> or <code>cr</code></li>
* <li><code>snapshot</code></li>
* <li><code>(the empty string)</code> or <code>ga</code> or <code>final</code></li>
* <li><code>sp</code></li>
* </ul>
* Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive),
* </li>
* <li>a dash usually precedes a qualifier, and is always less important than something preceded with a dot.</li>
* </ul></p>
*
* @see <a href="https://cwiki.apache.org/confluence/display/MAVENOLD/Versioning">"Versioning" on Maven Wiki</a>
* @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
* @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
*/
public class ComparableVersion
implements Comparable<ComparableVersion>
{
private String value;
private String canonical;
private ListItem items;
private interface Item
{
int INTEGER_ITEM = 0;
int STRING_ITEM = 1;
int LIST_ITEM = 2;
int compareTo( Item item );
int getType();
boolean isNull();
}
/**
* Represents a numeric item in the version item list.
*/
private static class IntegerItem
implements Item
{
private static final BigInteger BIG_INTEGER_ZERO = new BigInteger( "0" );
private final BigInteger value;
public static final IntegerItem ZERO = new IntegerItem();
private IntegerItem()
{
this.value = BIG_INTEGER_ZERO;
}
public IntegerItem( String str )
{
this.value = new BigInteger( str );
}
public int getType()
{
return INTEGER_ITEM;
}
public boolean isNull()
{
return BIG_INTEGER_ZERO.equals( value );
}
public int compareTo( Item item )
{
if ( item == null )
{
return BIG_INTEGER_ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1
}
switch ( item.getType() )
{
case INTEGER_ITEM:
return value.compareTo( ( (IntegerItem) item ).value );
case STRING_ITEM:
return 1; // 1.1 > 1-sp
case LIST_ITEM:
return 1; // 1.1 > 1-1
default:
throw new RuntimeException( "invalid item: " + item.getClass() );
}
}
public String toString()
{
return value.toString();
}
}
/**
* Represents a string in the version item list, usually a qualifier.
*/
private static class StringItem
implements Item
{
private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" };
private static final List<String> _QUALIFIERS = Arrays.asList( QUALIFIERS );
private static final Properties ALIASES = new Properties();
static
{
ALIASES.put( "ga", "" );
ALIASES.put( "final", "" );
ALIASES.put( "cr", "rc" );
}
/**
* A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes
* the version older than one without a qualifier, or more recent.
*/
private static final String RELEASE_VERSION_INDEX = String.valueOf( _QUALIFIERS.indexOf( "" ) );
private String value;
public StringItem( String value, boolean followedByDigit )
{
if ( followedByDigit && value.length() == 1 )
{
// a1 = alpha-1, b1 = beta-1, m1 = milestone-1
switch ( value.charAt( 0 ) )
{
case 'a':
value = "alpha";
break;
case 'b':
value = "beta";
break;
case 'm':
value = "milestone";
break;
}
}
this.value = ALIASES.getProperty( value , value );
}
public int getType()
{
return STRING_ITEM;
}
public boolean isNull()
{
return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 );
}
/**
* Returns a comparable value for a qualifier.
*
* This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical ordering.
*
* just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1
* or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character,
* so this is still fast. If more characters are needed then it requires a lexical sort anyway.
*
* @param qualifier
* @return an equivalent value that can be used with lexical comparison
*/
public static String comparableQualifier( String qualifier )
{
int i = _QUALIFIERS.indexOf( qualifier );
return i == -1 ? ( _QUALIFIERS.size() + "-" + qualifier ) : String.valueOf( i );
}
public int compareTo( Item item )
{
if ( item == null )
{
// 1-rc < 1, 1-ga > 1
return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX );
}
switch ( item.getType() )
{
case INTEGER_ITEM:
return -1; // 1.any < 1.1 ?
case STRING_ITEM:
return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) );
case LIST_ITEM:
return -1; // 1.any < 1-1
default:
throw new RuntimeException( "invalid item: " + item.getClass() );
}
}
public String toString()
{
return value;
}
}
/**
* Represents a version list item. This class is used both for the global item list and for sub-lists (which start
* with '-(number)' in the version specification).
*/
private static class ListItem
extends ArrayList<Item>
implements Item
{
private static final long serialVersionUID = 5914575811857700009L;
public int getType()
{
return LIST_ITEM;
}
public boolean isNull()
{
return ( size() == 0 );
}
void normalize()
{
for ( ListIterator<Item> iterator = listIterator( size() ); iterator.hasPrevious(); )
{
Item item = iterator.previous();
if ( item.isNull() )
{
iterator.remove(); // remove null trailing items: 0, "", empty list
}
else
{
break;
}
}
}
public int compareTo( Item item )
{
if ( item == null )
{
if ( size() == 0 )
{
return 0; // 1-0 = 1- (normalize) = 1
}
Item first = get( 0 );
return first.compareTo( null );
}
switch ( item.getType() )
{
case INTEGER_ITEM:
return -1; // 1-1 < 1.0.x
case STRING_ITEM:
return 1; // 1-1 > 1-sp
case LIST_ITEM:
Iterator<Item> left = iterator();
Iterator<Item> right = ( (ListItem) item ).iterator();
while ( left.hasNext() || right.hasNext() )
{
Item l = left.hasNext() ? left.next() : null;
Item r = right.hasNext() ? right.next() : null;
// if this is shorter, then invert the compare and mul with -1
int result = l == null ? ( r == null ? 0 : -1 * r.compareTo( l ) ) : l.compareTo( r );
if ( result != 0 )
{
return result;
}
}
return 0;
default:
throw new RuntimeException( "invalid item: " + item.getClass() );
}
}
public String toString()
{
StringBuilder buffer = new StringBuilder( "(" );
for ( Iterator<Item> iter = iterator(); iter.hasNext(); )
{
buffer.append( iter.next() );
if ( iter.hasNext() )
{
buffer.append( ',' );
}
}
buffer.append( ')' );
return buffer.toString();
}
}
public ComparableVersion( String version )
{
parseVersion( version );
}
public final void parseVersion( String version )
{
this.value = version;
items = new ListItem();
version = version.toLowerCase( Locale.ENGLISH );
ListItem list = items;
Stack<Item> stack = new Stack<Item>();
stack.push( list );
boolean isDigit = false;
int startIndex = 0;
for ( int i = 0; i < version.length(); i++ )
{
char c = version.charAt( i );
if ( c == '.' )
{
if ( i == startIndex )
{
list.add( IntegerItem.ZERO );
}
else
{
list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
}
startIndex = i + 1;
}
else if ( c == '-' )
{
if ( i == startIndex )
{
list.add( IntegerItem.ZERO );
}
else
{
list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
}
startIndex = i + 1;
if ( isDigit )
{
list.normalize(); // 1.0-* = 1-*
if ( ( i + 1 < version.length() ) && Character.isDigit( version.charAt( i + 1 ) ) )
{
// new ListItem only if previous were digits and new char is a digit,
// ie need to differentiate only 1.1 from 1-1
list.add( list = new ListItem() );
stack.push( list );
}
}
}
else if ( Character.isDigit( c ) )
{
if ( !isDigit && i > startIndex )
{
list.add( new StringItem( version.substring( startIndex, i ), true ) );
startIndex = i;
}
isDigit = true;
}
else
{
if ( isDigit && i > startIndex )
{
list.add( parseItem( true, version.substring( startIndex, i ) ) );
startIndex = i;
}
isDigit = false;
}
}
if ( version.length() > startIndex )
{
list.add( parseItem( isDigit, version.substring( startIndex ) ) );
}
while ( !stack.isEmpty() )
{
list = (ListItem) stack.pop();
list.normalize();
}
canonical = items.toString();
}
private static Item parseItem( boolean isDigit, String buf )
{
return isDigit ? new IntegerItem( buf ) : new StringItem( buf, false );
}
public int compareTo( ComparableVersion o )
{
return items.compareTo( o.items );
}
public String toString()
{
return value;
}
public boolean equals( Object o )
{
return ( o instanceof ComparableVersion ) && canonical.equals( ( (ComparableVersion) o ).canonical );
}
public int hashCode()
{
return canonical.hashCode();
}
}
package de.diddiz.LogBlock.util;
// Taken from maven-artifact at
// http://grepcode.com/file_/repo1.maven.org/maven2/org.apache.maven/maven-artifact/3.2.3/org/apache/maven/artifact/versioning/ComparableVersion.java/?v=source
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Properties;
import java.util.Stack;
/**
* Generic implementation of version comparison.
*
* <p>Features:
* <ul>
* <li>mixing of '<code>-</code>' (dash) and '<code>.</code>' (dot) separators,</li>
* <li>transition between characters and digits also constitutes a separator:
* <code>1.0alpha1 =&gt; [1, 0, alpha, 1]</code></li>
* <li>unlimited number of version components,</li>
* <li>version components in the text can be digits or strings,</li>
* <li>strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering.
* Well-known qualifiers (case insensitive) are:<ul>
* <li><code>alpha</code> or <code>a</code></li>
* <li><code>beta</code> or <code>b</code></li>
* <li><code>milestone</code> or <code>m</code></li>
* <li><code>rc</code> or <code>cr</code></li>
* <li><code>snapshot</code></li>
* <li><code>(the empty string)</code> or <code>ga</code> or <code>final</code></li>
* <li><code>sp</code></li>
* </ul>
* Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive),
* </li>
* <li>a dash usually precedes a qualifier, and is always less important than something preceded with a dot.</li>
* </ul></p>
*
* @see <a href="https://cwiki.apache.org/confluence/display/MAVENOLD/Versioning">"Versioning" on Maven Wiki</a>
* @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
* @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
*/
public class ComparableVersion implements Comparable<ComparableVersion> {
private String value;
private String canonical;
private ListItem items;
private interface Item {
int INTEGER_ITEM = 0;
int STRING_ITEM = 1;
int LIST_ITEM = 2;
int compareTo(Item item);
int getType();
boolean isNull();
}
/**
* Represents a numeric item in the version item list.
*/
private static class IntegerItem implements Item {
private static final BigInteger BIG_INTEGER_ZERO = new BigInteger("0");
private final BigInteger value;
public static final IntegerItem ZERO = new IntegerItem();
private IntegerItem() {
this.value = BIG_INTEGER_ZERO;
}
public IntegerItem(String str) {
this.value = new BigInteger(str);
}
@Override
public int getType() {
return INTEGER_ITEM;
}
@Override
public boolean isNull() {
return BIG_INTEGER_ZERO.equals(value);
}
@Override
public int compareTo(Item item) {
if (item == null) {
return BIG_INTEGER_ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1
}
switch (item.getType()) {
case INTEGER_ITEM:
return value.compareTo(((IntegerItem) item).value);
case STRING_ITEM:
return 1; // 1.1 > 1-sp
case LIST_ITEM:
return 1; // 1.1 > 1-1
default:
throw new RuntimeException("invalid item: " + item.getClass());
}
}
@Override
public String toString() {
return value.toString();
}
}
/**
* Represents a string in the version item list, usually a qualifier.
*/
private static class StringItem implements Item {
private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" };
private static final List<String> _QUALIFIERS = Arrays.asList(QUALIFIERS);
private static final Properties ALIASES = new Properties();
static {
ALIASES.put("ga", "");
ALIASES.put("final", "");
ALIASES.put("cr", "rc");
}
/**
* A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes
* the version older than one without a qualifier, or more recent.
*/
private static final String RELEASE_VERSION_INDEX = String.valueOf(_QUALIFIERS.indexOf(""));
private String value;
public StringItem(String value, boolean followedByDigit) {
if (followedByDigit && value.length() == 1) {
// a1 = alpha-1, b1 = beta-1, m1 = milestone-1
switch (value.charAt(0)) {
case 'a':
value = "alpha";
break;
case 'b':
value = "beta";
break;
case 'm':
value = "milestone";
break;
}
}
this.value = ALIASES.getProperty(value, value);
}
@Override
public int getType() {
return STRING_ITEM;
}
@Override
public boolean isNull() {
return (comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0);
}
/**
* Returns a comparable value for a qualifier.
*
* This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical ordering.
*
* just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1
* or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character,
* so this is still fast. If more characters are needed then it requires a lexical sort anyway.
*
* @param qualifier
* @return an equivalent value that can be used with lexical comparison
*/
public static String comparableQualifier(String qualifier) {
int i = _QUALIFIERS.indexOf(qualifier);
return i == -1 ? (_QUALIFIERS.size() + "-" + qualifier) : String.valueOf(i);
}
@Override
public int compareTo(Item item) {
if (item == null) {
// 1-rc < 1, 1-ga > 1
return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX);
}
switch (item.getType()) {
case INTEGER_ITEM:
return -1; // 1.any < 1.1 ?
case STRING_ITEM:
return comparableQualifier(value).compareTo(comparableQualifier(((StringItem) item).value));
case LIST_ITEM:
return -1; // 1.any < 1-1
default:
throw new RuntimeException("invalid item: " + item.getClass());
}
}
@Override
public String toString() {
return value;
}
}
/**
* Represents a version list item. This class is used both for the global item list and for sub-lists (which start
* with '-(number)' in the version specification).
*/
private static class ListItem extends ArrayList<Item> implements Item {
private static final long serialVersionUID = 5914575811857700009L;
@Override
public int getType() {
return LIST_ITEM;
}
@Override
public boolean isNull() {
return (size() == 0);
}
void normalize() {
for (ListIterator<Item> iterator = listIterator(size()); iterator.hasPrevious();) {
Item item = iterator.previous();
if (item.isNull()) {
iterator.remove(); // remove null trailing items: 0, "", empty list
} else {
break;
}
}
}
@Override
public int compareTo(Item item) {
if (item == null) {
if (size() == 0) {
return 0; // 1-0 = 1- (normalize) = 1
}
Item first = get(0);
return first.compareTo(null);
}
switch (item.getType()) {
case INTEGER_ITEM:
return -1; // 1-1 < 1.0.x
case STRING_ITEM:
return 1; // 1-1 > 1-sp
case LIST_ITEM:
Iterator<Item> left = iterator();
Iterator<Item> right = ((ListItem) item).iterator();
while (left.hasNext() || right.hasNext()) {
Item l = left.hasNext() ? left.next() : null;
Item r = right.hasNext() ? right.next() : null;
// if this is shorter, then invert the compare and mul with -1
int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r);
if (result != 0) {
return result;
}
}
return 0;
default:
throw new RuntimeException("invalid item: " + item.getClass());
}
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder("(");
for (Iterator<Item> iter = iterator(); iter.hasNext();) {
buffer.append(iter.next());
if (iter.hasNext()) {
buffer.append(',');
}
}
buffer.append(')');
return buffer.toString();
}
}
public ComparableVersion(String version) {
parseVersion(version);
}
public final void parseVersion(String version) {
this.value = version;
items = new ListItem();
version = version.toLowerCase(Locale.ENGLISH);
ListItem list = items;
Stack<Item> stack = new Stack<>();
stack.push(list);
boolean isDigit = false;
int startIndex = 0;
for (int i = 0; i < version.length(); i++) {
char c = version.charAt(i);
if (c == '.') {
if (i == startIndex) {
list.add(IntegerItem.ZERO);
} else {
list.add(parseItem(isDigit, version.substring(startIndex, i)));
}
startIndex = i + 1;
} else if (c == '-') {
if (i == startIndex) {
list.add(IntegerItem.ZERO);
} else {
list.add(parseItem(isDigit, version.substring(startIndex, i)));
}
startIndex = i + 1;
if (isDigit) {
list.normalize(); // 1.0-* = 1-*
if ((i + 1 < version.length()) && Character.isDigit(version.charAt(i + 1))) {
// new ListItem only if previous were digits and new char is a digit,
// ie need to differentiate only 1.1 from 1-1
list.add(list = new ListItem());
stack.push(list);
}
}
} else if (Character.isDigit(c)) {
if (!isDigit && i > startIndex) {
list.add(new StringItem(version.substring(startIndex, i), true));
startIndex = i;
}
isDigit = true;
} else {
if (isDigit && i > startIndex) {
list.add(parseItem(true, version.substring(startIndex, i)));
startIndex = i;
}
isDigit = false;
}
}
if (version.length() > startIndex) {
list.add(parseItem(isDigit, version.substring(startIndex)));
}
while (!stack.isEmpty()) {
list = (ListItem) stack.pop();
list.normalize();
}
canonical = items.toString();
}
private static Item parseItem(boolean isDigit, String buf) {
return isDigit ? new IntegerItem(buf) : new StringItem(buf, false);
}
@Override
public int compareTo(ComparableVersion o) {
return items.compareTo(o.items);
}
public int compareTo(String version) {
return compareTo(new ComparableVersion(version));
}
@Override
public String toString() {
return value;
}
public String toCanonicalString() {
return canonical;
}
@Override
public boolean equals(Object o) {
return (o instanceof ComparableVersion) && canonical.equals(((ComparableVersion) o).canonical);
}
@Override
public int hashCode() {
return canonical.hashCode();
}
}

View File

@ -0,0 +1,58 @@
package de.diddiz.LogBlock.util;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.util.BlockVector;
public class CuboidRegion implements Cloneable {
private World world;
private BlockVector min = new BlockVector();
private BlockVector max = new BlockVector();
public CuboidRegion(World world, BlockVector first, BlockVector second) {
this.world = world;
this.min.setX(Math.min(first.getBlockX(), second.getBlockX()));
this.min.setY(Math.min(first.getBlockY(), second.getBlockY()));
this.min.setZ(Math.min(first.getBlockZ(), second.getBlockZ()));
this.max.setX(Math.max(first.getBlockX(), second.getBlockX()));
this.max.setY(Math.max(first.getBlockY(), second.getBlockY()));
this.max.setZ(Math.max(first.getBlockZ(), second.getBlockZ()));
}
public static CuboidRegion fromCorners(World world, Location first, Location second) {
return new CuboidRegion(world, new BlockVector(first.getBlockX(), first.getBlockY(), first.getBlockZ()), new BlockVector(second.getBlockX(), second.getBlockY(), second.getBlockZ()));
}
public World getWorld() {
return world;
}
public BlockVector getMinimumPoint() {
return min;
}
public BlockVector getMaximumPoint() {
return max;
}
public int getSizeX() {
return max.getBlockX() - min.getBlockX() + 1;
}
public int getSizeZ() {
return max.getBlockZ() - min.getBlockZ() + 1;
}
@Override
public CuboidRegion clone() {
try {
CuboidRegion clone = (CuboidRegion) super.clone();
clone.min = min.clone();
clone.max = max.clone();
return clone;
} catch (final CloneNotSupportedException ex) {
throw new Error("CuboidRegion should be cloneable", ex);
}
}
}

View File

@ -0,0 +1,361 @@
package de.diddiz.LogBlock.util;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.Consumer;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.type.Bell;
import org.bukkit.block.data.type.Bell.Attachment;
import org.bukkit.block.data.type.Lantern;
import org.bukkit.block.data.type.PointedDripstone;
import org.bukkit.block.data.type.PointedDripstone.Thickness;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.projectiles.ProjectileSource;
import java.util.List;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import static de.diddiz.LogBlock.config.Config.mb4;
public class LoggingUtil {
public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState replaced, BlockState placed) {
Location loc = replaced.getLocation();
Material placedType = placed.getType();
if (!placedType.hasGravity() || !BukkitUtils.canDirectlyFallIn(replaced.getBlock().getRelative(BlockFace.DOWN).getType())) {
if (placedType == Material.TWISTING_VINES) {
Block below = placed.getBlock().getRelative(BlockFace.DOWN);
if (below.getType() == Material.TWISTING_VINES) {
consumer.queueBlockReplace(actor, below.getState(), Material.TWISTING_VINES_PLANT.createBlockData());
}
}
if (placedType == Material.WEEPING_VINES) {
Block above = placed.getBlock().getRelative(BlockFace.UP);
if (above.getType() == Material.WEEPING_VINES) {
consumer.queueBlockReplace(actor, above.getState(), Material.WEEPING_VINES_PLANT.createBlockData());
}
}
if (BukkitUtils.isEmpty(replaced.getType())) {
consumer.queueBlockPlace(actor, placed);
} else {
consumer.queueBlockReplace(actor, replaced, placed);
}
return;
}
int x = loc.getBlockX();
int initialy = loc.getBlockY();
int y = initialy;
int z = loc.getBlockZ();
while (y > loc.getWorld().getMinHeight() && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) {
y--;
}
if (initialy != y && !BukkitUtils.isEmpty(replaced.getType())) {
// this is not the final location but the block got removed (vines etc)
consumer.queueBlockBreak(actor, replaced);
}
// If y is minHeight then the block fell out of the world :(
if (y > loc.getWorld().getMinHeight()) {
// Run this check to avoid false positives
Location finalLoc = new Location(loc.getWorld(), x, y, z);
if (y == initialy || !BukkitUtils.isFallingEntityKiller(finalLoc.getBlock().getType())) {
if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) {
consumer.queueBlockPlace(actor, finalLoc, placed.getBlockData());
} else {
consumer.queueBlockReplace(actor, finalLoc.getBlock().getState(), placed.getBlockData());
}
}
}
}
public static void smartLogFallables(Consumer consumer, Actor actor, Block origin) {
WorldConfig wcfg = getWorldConfig(origin.getWorld());
if (wcfg == null) {
return;
}
//Handle falling blocks
Block checkBlock = origin.getRelative(BlockFace.UP);
int up = 0;
final int highestBlock = checkBlock.getWorld().getHighestBlockYAt(checkBlock.getLocation());
while (checkBlock.getType().hasGravity()) {
// Record this block as falling
consumer.queueBlockBreak(actor, checkBlock.getState());
// Guess where the block is going (This could be thrown of by explosions, but it is better than nothing)
Location loc = origin.getLocation();
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
while (y > loc.getWorld().getMinHeight() && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) {
y--;
}
// If y is minHeight then the sand block fell out of the world :(
if (y > loc.getWorld().getMinHeight()) {
Location finalLoc = new Location(loc.getWorld(), x, y, z);
// Run this check to avoid false positives
if (!BukkitUtils.isFallingEntityKiller(finalLoc.getBlock().getType())) {
finalLoc.add(0, up, 0); // Add this here after checking for block breakers
if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) {
consumer.queueBlockPlace(actor, finalLoc, checkBlock.getBlockData());
} else {
consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getBlockData(), checkBlock.getBlockData());
}
up++;
}
}
if (checkBlock.getY() >= highestBlock) {
break;
}
checkBlock = checkBlock.getRelative(BlockFace.UP);
}
if (wcfg.isLogging(Logging.SCAFFOLDING) && checkBlock.getType() == Material.SCAFFOLDING && consumer.getLogblock().getScaffoldingLogging() != null) {
consumer.getLogblock().getScaffoldingLogging().addScaffoldingBreaker(actor, checkBlock);
}
}
public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block origin) {
smartLogBlockReplace(consumer, actor, origin, null);
}
public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block origin, BlockData replacedWith) {
WorldConfig wcfg = getWorldConfig(origin.getWorld());
if (wcfg == null) {
return;
}
Material replacedType = origin.getType();
if (replacedType == Material.TWISTING_VINES || replacedType == Material.TWISTING_VINES_PLANT) {
Block below = origin.getRelative(BlockFace.DOWN);
if (below.getType() == Material.TWISTING_VINES_PLANT) {
consumer.queueBlockReplace(actor, below.getState(), Material.TWISTING_VINES.createBlockData());
}
}
if (replacedType == Material.WEEPING_VINES || replacedType == Material.WEEPING_VINES_PLANT) {
Block above = origin.getRelative(BlockFace.UP);
if (above.getType() == Material.WEEPING_VINES_PLANT) {
consumer.queueBlockReplace(actor, above.getState(), Material.WEEPING_VINES.createBlockData());
}
}
if (replacedType == Material.CAVE_VINES || replacedType == Material.CAVE_VINES_PLANT) {
Block above = origin.getRelative(BlockFace.UP);
if (above.getType() == Material.CAVE_VINES_PLANT) {
consumer.queueBlockReplace(actor, above.getState(), Material.CAVE_VINES.createBlockData());
}
}
Block checkBlock = origin.getRelative(BlockFace.UP);
Material typeAbove = checkBlock.getType();
if (BukkitUtils.isRelativeTopBreakable(typeAbove)) {
if (typeAbove == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(typeAbove)) {
Block doorBlock = checkBlock;
// If the doorBlock is the top half a door the player simply punched a door
// this will be handled later.
if (!BukkitUtils.isTop(doorBlock.getBlockData())) {
doorBlock = doorBlock.getRelative(BlockFace.UP);
// Fall back check just in case the top half wasn't a door
if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) {
consumer.queueBlockBreak(actor, doorBlock.getState());
}
consumer.queueBlockBreak(actor, checkBlock.getState());
}
} else if (BukkitUtils.isDoublePlant(typeAbove)) {
Block plantBlock = checkBlock;
// If the plantBlock is the top half of a double plant the player simply
// punched the plant this will be handled later.
if (!BukkitUtils.isTop(plantBlock.getBlockData())) {
plantBlock = plantBlock.getRelative(BlockFace.UP);
// Fall back check just in case the top half wasn't a plant
if (BukkitUtils.isDoublePlant(plantBlock.getType())) {
consumer.queueBlockBreak(actor, plantBlock.getState());
}
consumer.queueBlockBreak(actor, checkBlock.getState());
}
} else {
consumer.queueBlockBreak(actor, checkBlock.getState());
// check next blocks above
checkBlock = checkBlock.getRelative(BlockFace.UP);
typeAbove = checkBlock.getType();
while (BukkitUtils.isRelativeTopBreakable(typeAbove)) {
consumer.queueBlockBreak(actor, checkBlock.getState());
checkBlock = checkBlock.getRelative(BlockFace.UP);
typeAbove = checkBlock.getType();
}
}
} else if (typeAbove == Material.LANTERN) {
Lantern lantern = (Lantern) checkBlock.getBlockData();
if (!lantern.isHanging()) {
consumer.queueBlockBreak(actor, checkBlock.getState());
}
} else if (typeAbove == Material.BELL) {
Bell bell = (Bell) checkBlock.getBlockData();
if (bell.getAttachment() == Attachment.FLOOR) {
consumer.queueBlockBreak(actor, checkBlock.getState());
}
} else if (typeAbove == Material.POINTED_DRIPSTONE) {
Block dripStoneBlock = checkBlock;
while (true) {
if (dripStoneBlock.getType() != Material.POINTED_DRIPSTONE) {
break;
}
PointedDripstone dripstone = (PointedDripstone) dripStoneBlock.getBlockData();
if (dripstone.getVerticalDirection() != BlockFace.UP) {
if (dripstone.getThickness() == Thickness.TIP_MERGE) {
PointedDripstone newDripstone = (PointedDripstone) dripstone.clone();
newDripstone.setThickness(Thickness.TIP);
consumer.queueBlockReplace(actor, dripStoneBlock.getState(), newDripstone);
}
break;
}
consumer.queueBlockBreak(actor, dripStoneBlock.getState());
dripStoneBlock = dripStoneBlock.getRelative(BlockFace.UP);
}
}
checkBlock = origin.getRelative(BlockFace.DOWN);
Material typeBelow = checkBlock.getType();
if (typeBelow == Material.LANTERN) {
Lantern lantern = (Lantern) checkBlock.getBlockData();
if (lantern.isHanging()) {
consumer.queueBlockBreak(actor, checkBlock.getState());
}
} else if (BukkitUtils.isHangingSign(typeBelow)) {
consumer.queueBlockBreak(actor, checkBlock.getState());
} else if (typeBelow == Material.BELL) {
Bell bell = (Bell) checkBlock.getBlockData();
if (bell.getAttachment() == Attachment.CEILING) {
consumer.queueBlockBreak(actor, checkBlock.getState());
}
} else if (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT || typeBelow == Material.CAVE_VINES || typeBelow == Material.CAVE_VINES_PLANT) {
consumer.queueBlockBreak(actor, checkBlock.getState());
// check next blocks below
checkBlock = checkBlock.getRelative(BlockFace.DOWN);
typeBelow = checkBlock.getType();
while (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT || typeBelow == Material.CAVE_VINES || typeBelow == Material.CAVE_VINES_PLANT) {
consumer.queueBlockBreak(actor, checkBlock.getState());
checkBlock = checkBlock.getRelative(BlockFace.DOWN);
typeBelow = checkBlock.getType();
}
} else if ((replacedType == Material.BIG_DRIPLEAF || replacedType == Material.BIG_DRIPLEAF_STEM) && (typeBelow == Material.BIG_DRIPLEAF || typeBelow == Material.BIG_DRIPLEAF_STEM)) {
consumer.queueBlockBreak(actor, checkBlock.getState());
// check next blocks below
checkBlock = checkBlock.getRelative(BlockFace.DOWN);
typeBelow = checkBlock.getType();
while (typeBelow == Material.BIG_DRIPLEAF || typeBelow == Material.BIG_DRIPLEAF_STEM) {
consumer.queueBlockBreak(actor, checkBlock.getState());
checkBlock = checkBlock.getRelative(BlockFace.DOWN);
typeBelow = checkBlock.getType();
}
} else if (typeBelow == Material.POINTED_DRIPSTONE) {
Block dripStoneBlock = checkBlock;
while (true) {
if (dripStoneBlock.getType() != Material.POINTED_DRIPSTONE) {
break;
}
PointedDripstone dripstone = (PointedDripstone) dripStoneBlock.getBlockData();
if (dripstone.getVerticalDirection() != BlockFace.DOWN) {
if (dripstone.getThickness() == Thickness.TIP_MERGE) {
PointedDripstone newDripstone = (PointedDripstone) dripstone.clone();
newDripstone.setThickness(Thickness.TIP);
consumer.queueBlockReplace(actor, dripStoneBlock.getState(), newDripstone);
}
break;
}
consumer.queueBlockBreak(actor, dripStoneBlock.getState());
dripStoneBlock = dripStoneBlock.getRelative(BlockFace.DOWN);
}
}
List<Location> relativeBreakables = BukkitUtils.getBlocksNearby(origin, BukkitUtils.getRelativeBreakables());
if (!relativeBreakables.isEmpty()) {
for (Location location : relativeBreakables) {
Block block = location.getBlock();
BlockData blockData = block.getBlockData();
if (blockData instanceof Directional) {
if (blockData.getMaterial() == Material.BELL) {
if (((Bell) blockData).getAttachment() == Attachment.SINGLE_WALL) {
if (block.getRelative(((Bell) blockData).getFacing()).equals(origin)) {
consumer.queueBlockBreak(actor, block.getState());
}
}
} else {
if (block.getRelative(((Directional) blockData).getFacing().getOppositeFace()).equals(origin)) {
consumer.queueBlockBreak(actor, block.getState());
}
}
}
}
}
// Special door check
if (replacedType == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(replacedType)) {
Block doorBlock = origin;
// Up or down?
if (!BukkitUtils.isTop(doorBlock.getBlockData())) {
doorBlock = doorBlock.getRelative(BlockFace.UP);
} else {
doorBlock = doorBlock.getRelative(BlockFace.DOWN);
}
if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) {
consumer.queueBlockBreak(actor, doorBlock.getState());
}
} else if (BukkitUtils.isDoublePlant(replacedType)) { // Special double plant check
Block plantBlock = origin;
// Up or down?
if (!BukkitUtils.isTop(origin.getBlockData())) {
plantBlock = plantBlock.getRelative(BlockFace.UP);
} else {
plantBlock = plantBlock.getRelative(BlockFace.DOWN);
}
if (BukkitUtils.isDoublePlant(plantBlock.getType())) {
consumer.queueBlockBreak(actor, plantBlock.getState());
}
}
// Do this down here so that the block is added after blocks sitting on it
if (replacedWith == null) {
consumer.queueBlockBreak(actor, origin.getState());
} else {
consumer.queueBlockReplace(actor, origin.getState(), replacedWith);
}
}
public static String checkText(String text) {
if (text == null) {
return text;
}
if (mb4) {
return text;
}
return text.replaceAll("[^\\u0000-\\uFFFF]", "?");
}
public static Entity getRealDamager(Entity damager) {
if (damager instanceof Projectile) {
ProjectileSource realDamager = ((Projectile) damager).getShooter();
if (realDamager instanceof Entity) {
damager = (Entity) realDamager;
}
}
if (damager instanceof TNTPrimed) {
Entity realRemover = ((TNTPrimed) damager).getSource();
if (realRemover != null) {
damager = realRemover;
}
}
return damager;
}
}

View File

@ -0,0 +1,132 @@
package de.diddiz.LogBlock.util;
import static de.diddiz.LogBlock.util.ActionColor.CREATE;
import static de.diddiz.LogBlock.util.ActionColor.DESTROY;
import static de.diddiz.LogBlock.util.TypeColor.DEFAULT;
import static de.diddiz.LogBlock.util.Utils.spaces;
import de.diddiz.LogBlock.config.Config;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Text;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
public class MessagingUtil {
public static BaseComponent[] formatSummarizedChanges(int created, int destroyed, BaseComponent actor, int createdWidth, int destroyedWidth, float spaceFactor) {
TextComponent textCreated = createTextComponentWithColor(created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)), CREATE.getColor());
TextComponent textDestroyed = createTextComponentWithColor(destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)), DESTROY.getColor());
return new BaseComponent[] { textCreated, textDestroyed, actor };
}
public static TextComponent createTextComponentWithColor(String text, ChatColor color) {
TextComponent tc = new TextComponent(text);
tc.setColor(color);
return tc;
}
public static TextComponent brackets(BracketType type, BaseComponent... content) {
TextComponent tc = createTextComponentWithColor(type.getStarting(), TypeColor.BRACKETS.getColor());
for (BaseComponent c : content) {
tc.addExtra(c);
}
tc.addExtra(new TextComponent(type.getEnding()));
return tc;
}
public static TextComponent prettyDate(long date) {
TextComponent tc = brackets(BracketType.STANDARD, createTextComponentWithColor(Config.formatterShort.format(date), TypeColor.DATE.getColor()));
tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Config.formatter.format(date))));
return tc;
}
public static TextComponent prettyState(String stateName) {
return createTextComponentWithColor(stateName, TypeColor.STATE.getColor());
}
public static TextComponent prettyState(BaseComponent stateName) {
TextComponent tc = new TextComponent();
tc.setColor(TypeColor.STATE.getColor());
if (stateName != null) {
tc.addExtra(stateName);
}
return tc;
}
public static TextComponent prettyState(int stateValue) {
return prettyState(Integer.toString(stateValue));
}
public static <E extends Enum<E>> TextComponent prettyState(E enumerator) {
return prettyState(enumerator.toString());
}
public static TextComponent prettyMaterial(String materialName) {
return createTextComponentWithColor(materialName.toUpperCase(), TypeColor.MATERIAL.getColor());
}
public static TextComponent prettyMaterial(Material material) {
return prettyMaterial(material.name());
}
public static TextComponent prettyMaterial(BlockData material) {
TextComponent tc = prettyMaterial(material.getMaterial());
String bdString = material.getAsString();
int bracket = bdString.indexOf("[");
if (bracket >= 0) {
int bracket2 = bdString.indexOf("]", bracket);
if (bracket2 >= 0) {
String state = bdString.substring(bracket + 1, bracket2).replace(',', '\n');
tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(state)));
}
}
return tc;
}
public static TextComponent prettyEntityType(EntityType type) {
return prettyMaterial(type.name());
}
public static TextComponent prettyLocation(Location loc, int entryId) {
return prettyLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), entryId);
}
public static TextComponent prettyLocation(int x, int y, int z, int entryId) {
TextComponent tc = createTextComponentWithColor("", DEFAULT.getColor());
tc.addExtra(createTextComponentWithColor(Integer.toString(x), TypeColor.COORDINATE.getColor()));
tc.addExtra(createTextComponentWithColor(", ", DEFAULT.getColor()));
tc.addExtra(createTextComponentWithColor(Integer.toString(y), TypeColor.COORDINATE.getColor()));
tc.addExtra(createTextComponentWithColor(", ", DEFAULT.getColor()));
tc.addExtra(createTextComponentWithColor(Integer.toString(z), TypeColor.COORDINATE.getColor()));
if (entryId > 0) {
tc.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb tp " + entryId));
tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Teleport here")));
}
return tc;
}
public enum BracketType {
STANDARD("[", "]"),
ANGLE("<", ">");
private String starting, ending;
BracketType(String starting, String ending) {
this.starting = starting;
this.ending = ending;
}
public String getStarting() {
return starting;
}
public String getEnding() {
return ending;
}
}
}

View File

@ -1,51 +1,51 @@
package de.diddiz.util;
import com.zaxxer.hikari.HikariDataSource;
import de.diddiz.LogBlock.config.Config;
import java.io.Closeable;
import java.sql.Connection;
import java.sql.SQLException;
public class MySQLConnectionPool implements Closeable {
private final HikariDataSource ds;
public MySQLConnectionPool(String url, String user, String password, boolean requireSSL) {
this.ds = new HikariDataSource();
ds.setJdbcUrl(url);
ds.setUsername(user);
ds.setPassword(password);
ds.setMinimumIdle(2);
ds.setMaximumPoolSize(15);
ds.setPoolName("LogBlock-Connection-Pool");
ds.addDataSourceProperty("useUnicode", "true");
ds.addDataSourceProperty("characterEncoding", "utf-8");
ds.addDataSourceProperty("rewriteBatchedStatements", "true");
ds.addDataSourceProperty("cachePrepStmts", "true");
ds.addDataSourceProperty("prepStmtCacheSize", "250");
ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
ds.addDataSourceProperty("useServerPrepStmts", "true");
ds.addDataSourceProperty("useSSL", "true");
ds.addDataSourceProperty("requireSSL", Boolean.toString(requireSSL));
ds.addDataSourceProperty("verifyServerCertificate", "false");
}
@Override
public void close() {
ds.close();
}
public Connection getConnection() throws SQLException {
Connection connection = ds.getConnection();
if (Config.mb4) {
connection.createStatement().executeQuery("SET NAMES utf8mb4");
}
return connection;
}
}
package de.diddiz.LogBlock.util;
import com.zaxxer.hikari.HikariDataSource;
import de.diddiz.LogBlock.config.Config;
import java.io.Closeable;
import java.sql.Connection;
import java.sql.SQLException;
public class MySQLConnectionPool implements Closeable {
private final HikariDataSource ds;
public MySQLConnectionPool(String url, String user, String password, boolean useSSL, boolean requireSSL) {
this.ds = new HikariDataSource();
ds.setJdbcUrl(url);
ds.setUsername(user);
ds.setPassword(password);
ds.setMinimumIdle(2);
ds.setMaximumPoolSize(15);
ds.setPoolName("LogBlock-Connection-Pool");
ds.addDataSourceProperty("useUnicode", "true");
ds.addDataSourceProperty("characterEncoding", "utf-8");
ds.addDataSourceProperty("rewriteBatchedStatements", "true");
ds.addDataSourceProperty("cachePrepStmts", "true");
ds.addDataSourceProperty("prepStmtCacheSize", "250");
ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
ds.addDataSourceProperty("useServerPrepStmts", "true");
ds.addDataSourceProperty("useSSL", Boolean.toString(useSSL));
ds.addDataSourceProperty("requireSSL", Boolean.toString(requireSSL));
ds.addDataSourceProperty("verifyServerCertificate", "false");
}
@Override
public void close() {
ds.close();
}
public Connection getConnection() throws SQLException {
Connection connection = ds.getConnection();
if (Config.mb4) {
connection.createStatement().executeUpdate("SET NAMES utf8mb4");
}
return connection;
}
}

View File

@ -0,0 +1,27 @@
package de.diddiz.LogBlock.util;
import org.bukkit.Bukkit;
public class ReflectionUtil {
private static String versionString;
public static String getVersion() {
if (versionString == null) {
String name = Bukkit.getServer().getClass().getPackage().getName();
versionString = name.substring(name.lastIndexOf('.') + 1);
}
return versionString;
}
public static Class<?> getMinecraftClass(String minecraftClassName) throws ClassNotFoundException {
String clazzName = "net.minecraft." + minecraftClassName;
return Class.forName(clazzName);
}
public static Class<?> getCraftBukkitClass(String craftBukkitClassName) throws ClassNotFoundException {
String clazzName = "org.bukkit.craftbukkit." + getVersion() + "." + craftBukkitClassName;
return Class.forName(clazzName);
}
}

View File

@ -0,0 +1,24 @@
package de.diddiz.LogBlock.util;
public class SqlUtil {
public static String escapeString(String s) {
return escapeString(s, false);
}
public static String escapeString(String s, boolean escapeMatcher) {
s = s.replace("\u0000", "\\0");
s = s.replace("\u0026", "\\Z");
s = s.replace("\\", "\\\\");
s = s.replace("'", "\\'");
s = s.replace("\"", "\\\"");
s = s.replace("\b", "\\b");
s = s.replace("\n", "\\n");
s = s.replace("\r", "\\r");
s = s.replace("\t", "\\t");
if (escapeMatcher) {
s = s.replace("%", "\\%");
s = s.replace("_", "\\_");
}
return s;
}
}

View File

@ -0,0 +1,29 @@
package de.diddiz.LogBlock.util;
import net.md_5.bungee.api.ChatColor;
public enum TypeColor {
DEFAULT(ChatColor.YELLOW),
MATERIAL(ChatColor.BLUE),
STATE(ChatColor.BLUE),
DATE(ChatColor.DARK_AQUA),
BRACKETS(ChatColor.DARK_GRAY),
COORDINATE(ChatColor.WHITE),
HEADER(ChatColor.GOLD),
ERROR(ChatColor.RED);
private final ChatColor color;
TypeColor(ChatColor color) {
this.color = color;
}
public ChatColor getColor() {
return color;
}
@Override
public String toString() {
return color.toString();
}
}

View File

@ -1,79 +1,61 @@
package de.diddiz.util;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
// Adapted from https://gist.github.com/evilmidget38/26d70114b834f71fb3b4
public class UUIDFetcher {
private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft";
private static final JSONParser jsonParser = new JSONParser();
public static Map<String, UUID> getUUIDs(List<String> names) throws Exception {
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
HttpURLConnection connection = createConnection();
String body = JSONArray.toJSONString(names);
writeBody(connection, body);
JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream()));
for (Object profile : array) {
JSONObject jsonProfile = (JSONObject) profile;
String id = (String) jsonProfile.get("id");
String name = (String) jsonProfile.get("name");
UUID uuid = UUIDFetcher.getUUID(id);
uuidMap.put(name, uuid);
}
return uuidMap;
}
private static void writeBody(HttpURLConnection connection, String body) throws Exception {
OutputStream stream = connection.getOutputStream();
stream.write(body.getBytes());
stream.flush();
stream.close();
}
private static HttpURLConnection createConnection() throws Exception {
URL url = new URL(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);
return connection;
}
private static UUID getUUID(String id) {
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32));
}
public static byte[] toBytes(UUID uuid) {
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
byteBuffer.putLong(uuid.getMostSignificantBits());
byteBuffer.putLong(uuid.getLeastSignificantBits());
return byteBuffer.array();
}
public static UUID fromBytes(byte[] array) {
if (array.length != 16) {
throw new IllegalArgumentException("Illegal byte array length: " + array.length);
}
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
long mostSignificant = byteBuffer.getLong();
long leastSignificant = byteBuffer.getLong();
return new UUID(mostSignificant, leastSignificant);
}
}
package de.diddiz.LogBlock.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
// Adapted from https://gist.github.com/evilmidget38/26d70114b834f71fb3b4
public class UUIDFetcher {
private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft";
private static final Gson gson = new GsonBuilder().setLenient().create();
public static Map<String, UUID> getUUIDs(List<String> names) throws Exception {
Map<String, UUID> uuidMap = new HashMap<>();
HttpURLConnection connection = createConnection();
String body = gson.toJson(names);
writeBody(connection, body);
JsonArray array = gson.fromJson(new InputStreamReader(connection.getInputStream()), JsonArray.class);
for (JsonElement profile : array) {
JsonObject jsonProfile = (JsonObject) profile;
String id = jsonProfile.get("id").getAsString();
String name = jsonProfile.get("name").getAsString();
UUID uuid = getUUID(id);
uuidMap.put(name, uuid);
}
return uuidMap;
}
private static void writeBody(HttpURLConnection connection, String body) throws Exception {
OutputStream stream = connection.getOutputStream();
stream.write(body.getBytes());
stream.flush();
stream.close();
}
private static HttpURLConnection createConnection() throws Exception {
URL url = new URL(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);
return connection;
}
private static UUID getUUID(String id) {
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32));
}
}

View File

@ -1,287 +1,298 @@
package de.diddiz.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipException;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.LogBlock;
public class Utils {
public static String newline = System.getProperty("line.separator");
public static boolean isInt(String str) {
try {
Integer.parseInt(str);
return true;
} catch (final NumberFormatException ex) {
}
return false;
}
public static boolean isShort(String str) {
try {
Short.parseShort(str);
return true;
} catch (final NumberFormatException ex) {
}
return false;
}
public static boolean isByte(String str) {
try {
Byte.parseByte(str);
return true;
} catch (final NumberFormatException ex) {
}
return false;
}
public static String listing(String[] entries, String delimiter, String finalDelimiter) {
final int len = entries.length;
if (len == 0) {
return "";
}
if (len == 1) {
return entries[0];
}
final StringBuilder builder = new StringBuilder(entries[0]);
for (int i = 1; i < len - 1; i++) {
builder.append(delimiter).append(entries[i]);
}
builder.append(finalDelimiter).append(entries[len - 1]);
return builder.toString();
}
public static String listing(List<?> entries, String delimiter, String finalDelimiter) {
final int len = entries.size();
if (len == 0) {
return "";
}
if (len == 1) {
return entries.get(0).toString();
}
final StringBuilder builder = new StringBuilder(entries.get(0).toString());
for (int i = 1; i < len - 1; i++) {
builder.append(delimiter).append(entries.get(i).toString());
}
builder.append(finalDelimiter).append(entries.get(len - 1).toString());
return builder.toString();
}
public static int parseTimeSpec(String[] spec) {
if (spec == null || spec.length < 1 || spec.length > 2) {
return -1;
}
if (spec.length == 1 && isInt(spec[0])) {
return Integer.valueOf(spec[0]);
}
if (!spec[0].contains(":") && !spec[0].contains(".")) {
if (spec.length == 2) {
if (!isInt(spec[0])) {
return -1;
}
int min = Integer.parseInt(spec[0]);
if (spec[1].startsWith("h")) {
min *= 60;
} else if (spec[1].startsWith("d")) {
min *= 1440;
}
return min;
} else if (spec.length == 1) {
int days = 0, hours = 0, minutes = 0;
int lastIndex = 0, currIndex = 1;
while (currIndex <= spec[0].length()) {
while (currIndex <= spec[0].length() && isInt(spec[0].substring(lastIndex, currIndex))) {
currIndex++;
}
if (currIndex - 1 != lastIndex) {
if (currIndex > spec[0].length()) {
return -1;
}
final String param = spec[0].substring(currIndex - 1, currIndex).toLowerCase();
if (param.equals("d")) {
days = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
} else if (param.equals("h")) {
hours = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
} else if (param.equals("m")) {
minutes = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
}
}
lastIndex = currIndex;
currIndex++;
}
if (days == 0 && hours == 0 && minutes == 0) {
return -1;
}
return minutes + hours * 60 + days * 1440;
} else {
return -1;
}
}
final String timestamp;
if (spec.length == 1) {
if (spec[0].contains(":")) {
timestamp = new SimpleDateFormat("dd.MM.yyyy").format(System.currentTimeMillis()) + " " + spec[0];
} else {
timestamp = spec[0] + " 00:00:00";
}
} else {
timestamp = spec[0] + " " + spec[1];
}
try {
return (int) ((System.currentTimeMillis() - new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").parse(timestamp).getTime()) / 60000);
} catch (final ParseException ex) {
return -1;
}
}
public static String spaces(int count) {
final StringBuilder filled = new StringBuilder(count);
for (int i = 0; i < count; i++) {
filled.append(' ');
}
return filled.toString();
}
public static String join(String[] s, String delimiter) {
if (s == null || s.length == 0) {
return "";
}
final int len = s.length;
final StringBuilder builder = new StringBuilder(s[0]);
for (int i = 1; i < len; i++) {
builder.append(delimiter).append(s[i]);
}
return builder.toString();
}
/**
* Converts a list of arguments e.g ['lb', 'clearlog', 'world', '"my', 'world', 'of', 'swag"']
* into a list of arguments with any text encapsulated by quotes treated as one word
* For this particular example: ['lb', 'clearlog', 'world', '"my world of swag"']
*
* @param args The list of arguments
* @return A new list with the quoted arguments parsed to single values
*/
public static List<String> parseQuotes(List<String> args) {
List<String> newArguments = new ArrayList<String>();
String subjectString = join(args.toArray(new String[args.size()]), " ");
Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
newArguments.add(regexMatcher.group());
}
return newArguments;
}
public static class ExtensionFilenameFilter implements FilenameFilter {
private final String ext;
public ExtensionFilenameFilter(String ext) {
this.ext = "." + ext;
}
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(ext);
}
}
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String mysqlEscapeBytes(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2 + 2];
hexChars[0] = '0';
hexChars[1] = 'x';
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2 + 2] = hexArray[v >>> 4];
hexChars[j * 2 + 3] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static String mysqlPrepareBytesForInsertAllowNull(byte[] bytes) {
if (bytes == null) {
return "null";
}
return "'" + mysqlEscapeBytes(bytes) + "'";
}
public static String mysqlTextEscape(String untrusted) {
return untrusted.replace("\\", "\\\\").replace("'", "\\'");
}
public static ItemStack loadItemStack(byte[] data) {
if (data == null || data.length == 0) {
return null;
}
YamlConfiguration conf = deserializeYamlConfiguration(data);
return conf == null ? null : conf.getItemStack("stack");
}
public static byte[] saveItemStack(ItemStack stack) {
if (stack == null || BukkitUtils.isEmpty(stack.getType())) {
return null;
}
YamlConfiguration conf = new YamlConfiguration();
conf.set("stack", stack);
return serializeYamlConfiguration(conf);
}
public static YamlConfiguration deserializeYamlConfiguration(byte[] data) {
if (data == null || data.length == 0) {
return null;
}
YamlConfiguration conf = new YamlConfiguration();
try {
InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8");
conf.load(reader);
reader.close();
return conf;
} catch (ZipException | InvalidConfigurationException e) {
LogBlock.getInstance().getLogger().warning("Could not deserialize YamlConfiguration: " + e.getMessage());
return conf;
} catch (IOException e) {
throw new RuntimeException("IOException should be impossible for ByteArrayInputStream", e);
}
}
public static byte[] serializeYamlConfiguration(YamlConfiguration conf) {
if (conf == null || conf.getKeys(false).isEmpty()) {
return null;
}
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8");
writer.write(conf.saveToString());
writer.close();
return baos.toByteArray();
} catch (IOException e) {
throw new RuntimeException("IOException should be impossible for ByteArrayOutputStream", e);
}
}
public static String serializeForSQL(YamlConfiguration conf) {
return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf));
}
}
package de.diddiz.LogBlock.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipException;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.LogBlock;
public class Utils {
public static String newline = System.getProperty("line.separator");
public static boolean isInt(String str) {
try {
Integer.parseInt(str);
return true;
} catch (final NumberFormatException ex) {
}
return false;
}
public static boolean isShort(String str) {
try {
Short.parseShort(str);
return true;
} catch (final NumberFormatException ex) {
}
return false;
}
public static boolean isByte(String str) {
try {
Byte.parseByte(str);
return true;
} catch (final NumberFormatException ex) {
}
return false;
}
public static String listing(String[] entries, String delimiter, String finalDelimiter) {
final int len = entries.length;
if (len == 0) {
return "";
}
if (len == 1) {
return entries[0];
}
final StringBuilder builder = new StringBuilder(entries[0]);
for (int i = 1; i < len - 1; i++) {
builder.append(delimiter).append(entries[i]);
}
builder.append(finalDelimiter).append(entries[len - 1]);
return builder.toString();
}
public static String listing(List<?> entries, String delimiter, String finalDelimiter) {
final int len = entries.size();
if (len == 0) {
return "";
}
if (len == 1) {
return entries.get(0).toString();
}
final StringBuilder builder = new StringBuilder(entries.get(0).toString());
for (int i = 1; i < len - 1; i++) {
builder.append(delimiter).append(entries.get(i).toString());
}
builder.append(finalDelimiter).append(entries.get(len - 1).toString());
return builder.toString();
}
public static int parseTimeSpec(String[] spec) {
if (spec == null || spec.length < 1 || spec.length > 2) {
return -1;
}
if (spec.length == 1 && isInt(spec[0])) {
return Integer.valueOf(spec[0]);
}
if (!spec[0].contains(":") && !spec[0].contains(".")) {
if (spec.length == 2) {
if (!isInt(spec[0])) {
return -1;
}
int min = Integer.parseInt(spec[0]);
if (spec[1].startsWith("h")) {
min *= 60;
} else if (spec[1].startsWith("d")) {
min *= 1440;
}
return min;
} else if (spec.length == 1) {
int days = 0, hours = 0, minutes = 0;
int lastIndex = 0, currIndex = 1;
while (currIndex <= spec[0].length()) {
while (currIndex <= spec[0].length() && isInt(spec[0].substring(lastIndex, currIndex))) {
currIndex++;
}
if (currIndex - 1 != lastIndex) {
if (currIndex > spec[0].length()) {
return -1;
}
final String param = spec[0].substring(currIndex - 1, currIndex).toLowerCase();
if (param.equals("d")) {
days = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
} else if (param.equals("h")) {
hours = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
} else if (param.equals("m")) {
minutes = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
}
}
lastIndex = currIndex;
currIndex++;
}
if (days == 0 && hours == 0 && minutes == 0) {
return -1;
}
return minutes + hours * 60 + days * 1440;
} else {
return -1;
}
}
final String timestamp;
if (spec.length == 1) {
if (spec[0].contains(":")) {
timestamp = new SimpleDateFormat("dd.MM.yyyy").format(System.currentTimeMillis()) + " " + spec[0];
} else {
timestamp = spec[0] + " 00:00:00";
}
} else {
timestamp = spec[0] + " " + spec[1];
}
try {
return (int) ((System.currentTimeMillis() - new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").parse(timestamp).getTime()) / 60000);
} catch (final ParseException ex) {
return -1;
}
}
public static String spaces(int count) {
final StringBuilder filled = new StringBuilder(count);
for (int i = 0; i < count; i++) {
filled.append(' ');
}
return filled.toString();
}
public static String join(String[] s, String delimiter) {
if (s == null || s.length == 0) {
return "";
}
final int len = s.length;
final StringBuilder builder = new StringBuilder(s[0]);
for (int i = 1; i < len; i++) {
builder.append(delimiter).append(s[i]);
}
return builder.toString();
}
/**
* Converts a list of arguments e.g ['lb', 'clearlog', 'world', '"my', 'world', 'of', 'swag"']
* into a list of arguments with any text encapsulated by quotes treated as one word
* For this particular example: ['lb', 'clearlog', 'world', '"my world of swag"']
*
* @param args The list of arguments
* @return A new list with the quoted arguments parsed to single values
*/
public static List<String> parseQuotes(List<String> args) {
List<String> newArguments = new ArrayList<>();
String subjectString = join(args.toArray(new String[args.size()]), " ");
Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
newArguments.add(regexMatcher.group());
}
return newArguments;
}
public static class ExtensionFilenameFilter implements FilenameFilter {
private final String ext;
public ExtensionFilenameFilter(String ext) {
this.ext = "." + ext;
}
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(ext);
}
}
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String mysqlEscapeBytes(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2 + 2];
hexChars[0] = '0';
hexChars[1] = 'x';
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2 + 2] = hexArray[v >>> 4];
hexChars[j * 2 + 3] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static String mysqlPrepareBytesForInsertAllowNull(byte[] bytes) {
if (bytes == null) {
return "null";
}
return "'" + mysqlEscapeBytes(bytes) + "'";
}
public static String mysqlTextEscape(String untrusted) {
return untrusted.replace("\\", "\\\\").replace("'", "\\'");
}
public static ItemStack loadItemStack(byte[] data) {
if (data == null || data.length == 0) {
return null;
}
YamlConfiguration conf = deserializeYamlConfiguration(data);
return conf == null ? null : conf.getItemStack("stack");
}
public static byte[] saveItemStack(ItemStack stack) {
if (stack == null || BukkitUtils.isEmpty(stack.getType())) {
return null;
}
YamlConfiguration conf = new YamlConfiguration();
conf.set("stack", stack);
return serializeYamlConfiguration(conf);
}
public static YamlConfiguration deserializeYamlConfiguration(byte[] data) {
if (data == null || data.length == 0) {
return null;
}
YamlConfiguration conf = new YamlConfiguration();
try {
InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8");
conf.load(reader);
reader.close();
return conf;
} catch (ZipException | InvalidConfigurationException e) {
LogBlock.getInstance().getLogger().warning("Could not deserialize YamlConfiguration: " + e.getMessage());
return conf;
} catch (IOException e) {
throw new RuntimeException("IOException should be impossible for ByteArrayInputStream", e);
}
}
public static byte[] serializeYamlConfiguration(YamlConfiguration conf) {
if (conf == null || conf.getKeys(false).isEmpty()) {
return null;
}
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8");
writer.write(conf.saveToString());
writer.close();
return baos.toByteArray();
} catch (IOException e) {
throw new RuntimeException("IOException should be impossible for ByteArrayOutputStream", e);
}
}
public static String serializeForSQL(YamlConfiguration conf) {
return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf));
}
public static double warpDegrees(double degrees) {
double d = degrees % 360.0;
if (d >= 180.0) {
d -= 360.0;
}
if (d < -180.0) {
d += 360.0;
}
return d;
}
}

View File

@ -1,4 +1,4 @@
package de.diddiz.worldedit;
package de.diddiz.LogBlock.worldedit;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -11,10 +11,12 @@ import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.BlockVector;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.DoubleTag;
import com.sk89q.jnbt.FloatTag;
@ -24,11 +26,15 @@ import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.util.CuboidRegion;
public class WorldEditHelper {
private static boolean checkedForWorldEdit;
@ -58,9 +64,19 @@ public class WorldEditHelper {
}
public static Entity restoreEntity(Location location, EntityType type, byte[] serialized) {
if (!hasWorldEdit()) {
return null;
}
return Internal.restoreEntity(location, type, serialized);
}
public static CuboidRegion getSelectedRegion(Player player) throws IllegalArgumentException {
if (!hasWorldEdit()) {
throw new IllegalArgumentException("WorldEdit not found!");
}
return Internal.getSelectedRegion(player);
}
private static class Internal {
private static WorldEditPlugin worldEdit;
private static Method getBukkitImplAdapter;
@ -101,7 +117,12 @@ public class WorldEditHelper {
com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state);
if (weEntity != null) {
CompoundTag newNbt = weEntity.getState().getNbtData();
newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast"));
int[] uuidInts = newNbt.getIntArray("UUID");
if (uuidInts != null && uuidInts.length >= 4) {
newUUID = new UUID(((long) uuidInts[0] << 32) | (uuidInts[1] & 0xFFFFFFFFL), ((long) uuidInts[2] << 32) | (uuidInts[3] & 0xFFFFFFFFL));
} else {
newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); // pre 1.16
}
}
}
return newUUID == null ? null : Bukkit.getEntity(newUUID);
@ -118,7 +139,7 @@ public class WorldEditHelper {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
NBTOutputStream nbtos = new NBTOutputStream(baos);
CompoundTag nbt = state.getNbtData();
LinkedHashMap<String, Tag> value = new LinkedHashMap<>(nbt.getValue());
LinkedHashMap<String, Tag<?, ?>> value = new LinkedHashMap<>(nbt.getValue());
value.put("Health", new FloatTag(20.0f));
value.put("Motion", new ListTag(DoubleTag.class, Arrays.asList(new DoubleTag[] { new DoubleTag(0), new DoubleTag(0), new DoubleTag(0) })));
value.put("Fire", new ShortTag((short) -20));
@ -133,5 +154,28 @@ public class WorldEditHelper {
return null;
}
public static CuboidRegion getSelectedRegion(Player player) throws IllegalArgumentException {
LocalSession session = worldEdit.getSession(player);
World world = player.getWorld();
com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world);
if (!weWorld.equals(session.getSelectionWorld())) {
throw new IllegalArgumentException("No selection defined");
}
Region selection;
try {
selection = session.getSelection(weWorld);
} catch (IncompleteRegionException e) {
throw new IllegalArgumentException("No selection defined");
}
if (selection == null) {
throw new IllegalArgumentException("No selection defined");
}
if (!(selection instanceof com.sk89q.worldedit.regions.CuboidRegion)) {
throw new IllegalArgumentException("You have to define a cuboid selection");
}
BlockVector3 min = selection.getMinimumPoint();
BlockVector3 max = selection.getMaximumPoint();
return new CuboidRegion(world, new BlockVector(min.getBlockX(), min.getBlockY(), min.getBlockZ()), new BlockVector(max.getBlockX(), max.getBlockY(), max.getBlockZ()));
}
}
}

View File

@ -1,4 +1,4 @@
package de.diddiz.worldedit;
package de.diddiz.LogBlock.worldedit;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
@ -15,8 +15,7 @@ import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.util.BukkitUtils;
import de.diddiz.LogBlock.util.BukkitUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
@ -74,26 +73,30 @@ public class WorldEditLoggingHook {
onBlockChange(position, block);
return super.setBlock(position, block);
}
protected <B extends BlockStateHolder<B>> void onBlockChange(BlockVector3 pt, B block) {
if (event.getStage() != EditSession.Stage.BEFORE_CHANGE) {
return;
}
Location location = new Location(world, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
Block origin = location.getBlock();
Material typeBefore = origin.getType();
Location location = BukkitAdapter.adapt(world, pt);
Block blockBefore = location.getBlock();
BlockData blockDataBefore = blockBefore.getBlockData();
Material typeBefore = blockDataBefore.getMaterial();
// Check to see if we've broken a sign
if (BlockStateCodecs.hasCodec(typeBefore)) {
plugin.getConsumer().queueBlockBreak(lbActor, origin.getState());
} else if (!origin.isEmpty()) {
plugin.getConsumer().queueBlockBreak(lbActor, location, origin.getBlockData());
}
BlockData newBlock = BukkitAdapter.adapt(block);
if (newBlock != null && !BukkitUtils.isEmpty(newBlock.getMaterial())) {
plugin.getConsumer().queueBlockPlace(lbActor, location, newBlock);
BlockData blockDataNew = BukkitAdapter.adapt(block);
if (!blockDataBefore.equals(blockDataNew)) {
// Check to see if we've broken a sign
if (BlockStateCodecs.hasCodec(typeBefore)) {
plugin.getConsumer().queueBlockBreak(lbActor, blockBefore.getState());
} else if (!BukkitUtils.isEmpty(typeBefore)) {
plugin.getConsumer().queueBlockBreak(lbActor, location, blockDataBefore);
}
if (!BukkitUtils.isEmpty(blockDataNew.getMaterial())) {
plugin.getConsumer().queueBlockPlace(lbActor, location, blockDataNew);
}
}
}
});

View File

@ -1,896 +0,0 @@
package de.diddiz.util;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.DoubleChest;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.Bisected.Half;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Slab;
import org.bukkit.block.data.type.Slab.Type;
import org.bukkit.block.data.type.Stairs;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import java.io.File;
import java.util.*;
import java.util.Map.Entry;
public class BukkitUtils {
private static final Set<Set<Integer>> blockEquivalents;
private static final Set<Material> relativeBreakable;
private static final Set<Material> relativeTopBreakable;
private static final Set<Material> fallingEntityKillers;
private static final Set<Material> cropBlocks;
private static final Set<Material> containerBlocks;
private static final Set<Material> singleBlockPlants;
private static final Set<Material> doublePlants;
private static final Set<Material> nonFluidProofBlocks;
private static final Set<Material> bedBlocks;
private static final Map<EntityType, Material> projectileItems;
private static final EnumSet<Material> buttons;
private static final EnumSet<Material> pressurePlates;
private static final EnumSet<Material> woodenDoors;
private static final EnumSet<Material> slabs;
private static final EnumSet<Material> concreteBlocks;
static {
pressurePlates = EnumSet.noneOf(Material.class);
pressurePlates.add(Material.OAK_PRESSURE_PLATE);
pressurePlates.add(Material.SPRUCE_PRESSURE_PLATE);
pressurePlates.add(Material.BIRCH_PRESSURE_PLATE);
pressurePlates.add(Material.JUNGLE_PRESSURE_PLATE);
pressurePlates.add(Material.ACACIA_PRESSURE_PLATE);
pressurePlates.add(Material.DARK_OAK_PRESSURE_PLATE);
pressurePlates.add(Material.STONE_PRESSURE_PLATE);
pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE);
pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE);
woodenDoors = EnumSet.noneOf(Material.class);
woodenDoors.add(Material.OAK_DOOR);
woodenDoors.add(Material.SPRUCE_DOOR);
woodenDoors.add(Material.BIRCH_DOOR);
woodenDoors.add(Material.JUNGLE_DOOR);
woodenDoors.add(Material.ACACIA_DOOR);
woodenDoors.add(Material.DARK_OAK_DOOR);
EnumSet<Material> saplings = EnumSet.noneOf(Material.class);
saplings.add(Material.OAK_SAPLING);
saplings.add(Material.SPRUCE_SAPLING);
saplings.add(Material.BIRCH_SAPLING);
saplings.add(Material.JUNGLE_SAPLING);
saplings.add(Material.ACACIA_SAPLING);
saplings.add(Material.DARK_OAK_SAPLING);
EnumSet<Material> carpets = EnumSet.noneOf(Material.class);
carpets.add(Material.BLACK_CARPET);
carpets.add(Material.BLUE_CARPET);
carpets.add(Material.LIGHT_GRAY_CARPET);
carpets.add(Material.BROWN_CARPET);
carpets.add(Material.CYAN_CARPET);
carpets.add(Material.GRAY_CARPET);
carpets.add(Material.GREEN_CARPET);
carpets.add(Material.LIGHT_BLUE_CARPET);
carpets.add(Material.MAGENTA_CARPET);
carpets.add(Material.LIME_CARPET);
carpets.add(Material.ORANGE_CARPET);
carpets.add(Material.PINK_CARPET);
carpets.add(Material.PURPLE_CARPET);
carpets.add(Material.RED_CARPET);
carpets.add(Material.WHITE_CARPET);
carpets.add(Material.YELLOW_CARPET);
slabs = EnumSet.noneOf(Material.class);
slabs.add(Material.OAK_SLAB);
slabs.add(Material.SPRUCE_SLAB);
slabs.add(Material.BIRCH_SLAB);
slabs.add(Material.JUNGLE_SLAB);
slabs.add(Material.ACACIA_SLAB);
slabs.add(Material.DARK_OAK_SLAB);
slabs.add(Material.STONE_SLAB);
slabs.add(Material.STONE_BRICK_SLAB);
slabs.add(Material.COBBLESTONE_SLAB);
slabs.add(Material.PETRIFIED_OAK_SLAB);
slabs.add(Material.SANDSTONE_SLAB);
slabs.add(Material.RED_SANDSTONE_SLAB);
slabs.add(Material.NETHER_BRICK_SLAB);
slabs.add(Material.PURPUR_SLAB);
slabs.add(Material.QUARTZ_SLAB);
slabs.add(Material.BRICK_SLAB);
slabs.add(Material.PRISMARINE_SLAB);
slabs.add(Material.DARK_PRISMARINE_SLAB);
slabs.add(Material.PRISMARINE_BRICK_SLAB);
buttons = EnumSet.noneOf(Material.class);
buttons.add(Material.STONE_BUTTON);
buttons.add(Material.OAK_BUTTON);
buttons.add(Material.SPRUCE_BUTTON);
buttons.add(Material.BIRCH_BUTTON);
buttons.add(Material.JUNGLE_BUTTON);
buttons.add(Material.ACACIA_BUTTON);
buttons.add(Material.DARK_OAK_BUTTON);
singleBlockPlants = EnumSet.noneOf(Material.class);
singleBlockPlants.add(Material.GRASS);
singleBlockPlants.add(Material.FERN);
singleBlockPlants.add(Material.DEAD_BUSH);
singleBlockPlants.add(Material.DANDELION);
singleBlockPlants.add(Material.POPPY);
singleBlockPlants.add(Material.BLUE_ORCHID);
singleBlockPlants.add(Material.ALLIUM);
singleBlockPlants.add(Material.AZURE_BLUET);
singleBlockPlants.add(Material.ORANGE_TULIP);
singleBlockPlants.add(Material.WHITE_TULIP);
singleBlockPlants.add(Material.PINK_TULIP);
singleBlockPlants.add(Material.RED_TULIP);
singleBlockPlants.add(Material.OXEYE_DAISY);
singleBlockPlants.add(Material.BROWN_MUSHROOM);
singleBlockPlants.add(Material.RED_MUSHROOM);
doublePlants = EnumSet.noneOf(Material.class);
doublePlants.add(Material.TALL_GRASS);
doublePlants.add(Material.LARGE_FERN);
doublePlants.add(Material.TALL_SEAGRASS);
doublePlants.add(Material.ROSE_BUSH);
doublePlants.add(Material.LILAC);
doublePlants.add(Material.SUNFLOWER);
doublePlants.add(Material.PEONY);
blockEquivalents = new HashSet<Set<Integer>>(7);
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(2, 3, 60)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(8, 9, 79)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(10, 11)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(61, 62)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(73, 74)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(75, 76)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(93, 94)));
// Blocks that break when they are attached to a block
relativeBreakable = EnumSet.noneOf(Material.class);
relativeBreakable.add(Material.WALL_SIGN);
relativeBreakable.add(Material.LADDER);
relativeBreakable.addAll(buttons);
relativeBreakable.add(Material.REDSTONE_WALL_TORCH);
relativeBreakable.add(Material.LEVER);
relativeBreakable.add(Material.WALL_TORCH);
relativeBreakable.add(Material.TRIPWIRE_HOOK);
relativeBreakable.add(Material.COCOA);
// Blocks that break when they are on top of a block
relativeTopBreakable = EnumSet.noneOf(Material.class);
relativeTopBreakable.addAll(saplings);
relativeTopBreakable.addAll(singleBlockPlants);
relativeTopBreakable.add(Material.WHEAT);
relativeTopBreakable.add(Material.POTATO);
relativeTopBreakable.add(Material.CARROT);
relativeTopBreakable.add(Material.LILY_PAD);
relativeTopBreakable.add(Material.CACTUS);
relativeTopBreakable.add(Material.SUGAR_CANE);
relativeTopBreakable.add(Material.FLOWER_POT);
relativeTopBreakable.add(Material.POWERED_RAIL);
relativeTopBreakable.add(Material.DETECTOR_RAIL);
relativeTopBreakable.add(Material.ACTIVATOR_RAIL);
relativeTopBreakable.add(Material.RAIL);
relativeTopBreakable.add(Material.REDSTONE_WIRE);
relativeTopBreakable.add(Material.SIGN);
relativeTopBreakable.addAll(pressurePlates);
relativeTopBreakable.add(Material.SNOW);
relativeTopBreakable.add(Material.REPEATER);
relativeTopBreakable.add(Material.COMPARATOR);
relativeTopBreakable.add(Material.TORCH);
relativeTopBreakable.add(Material.WALL_TORCH);
relativeTopBreakable.add(Material.REDSTONE_TORCH);
relativeTopBreakable.add(Material.REDSTONE_WALL_TORCH);
relativeTopBreakable.addAll(woodenDoors);
relativeTopBreakable.add(Material.IRON_DOOR);
relativeTopBreakable.addAll(carpets);
relativeTopBreakable.addAll(doublePlants);
// Blocks that break falling entities
fallingEntityKillers = EnumSet.noneOf(Material.class);
fallingEntityKillers.add(Material.SIGN);
fallingEntityKillers.add(Material.WALL_SIGN);
fallingEntityKillers.addAll(pressurePlates);
fallingEntityKillers.addAll(saplings);
fallingEntityKillers.add(Material.DANDELION);
fallingEntityKillers.add(Material.POPPY);
fallingEntityKillers.add(Material.BLUE_ORCHID);
fallingEntityKillers.add(Material.ALLIUM);
fallingEntityKillers.add(Material.AZURE_BLUET);
fallingEntityKillers.add(Material.ORANGE_TULIP);
fallingEntityKillers.add(Material.WHITE_TULIP);
fallingEntityKillers.add(Material.PINK_TULIP);
fallingEntityKillers.add(Material.RED_TULIP);
fallingEntityKillers.add(Material.OXEYE_DAISY);
fallingEntityKillers.add(Material.BROWN_MUSHROOM);
fallingEntityKillers.add(Material.RED_MUSHROOM);
fallingEntityKillers.addAll(doublePlants);
fallingEntityKillers.add(Material.WHEAT);
fallingEntityKillers.add(Material.CARROT);
fallingEntityKillers.add(Material.POTATO);
fallingEntityKillers.add(Material.BEETROOT);
fallingEntityKillers.add(Material.NETHER_WART);
fallingEntityKillers.add(Material.COCOA);
fallingEntityKillers.addAll(slabs);
fallingEntityKillers.add(Material.TORCH);
fallingEntityKillers.add(Material.WALL_TORCH);
fallingEntityKillers.add(Material.FLOWER_POT);
fallingEntityKillers.add(Material.POWERED_RAIL);
fallingEntityKillers.add(Material.DETECTOR_RAIL);
fallingEntityKillers.add(Material.ACTIVATOR_RAIL);
fallingEntityKillers.add(Material.RAIL);
fallingEntityKillers.add(Material.LEVER);
fallingEntityKillers.add(Material.REDSTONE_WIRE);
fallingEntityKillers.add(Material.REDSTONE_TORCH);
fallingEntityKillers.add(Material.REDSTONE_WALL_TORCH);
fallingEntityKillers.add(Material.REPEATER);
fallingEntityKillers.add(Material.COMPARATOR);
fallingEntityKillers.add(Material.DAYLIGHT_DETECTOR);
fallingEntityKillers.addAll(carpets);
fallingEntityKillers.add(Material.PLAYER_HEAD);
fallingEntityKillers.add(Material.PLAYER_WALL_HEAD);
fallingEntityKillers.add(Material.CREEPER_HEAD);
fallingEntityKillers.add(Material.CREEPER_WALL_HEAD);
fallingEntityKillers.add(Material.DRAGON_HEAD);
fallingEntityKillers.add(Material.DRAGON_WALL_HEAD);
fallingEntityKillers.add(Material.ZOMBIE_HEAD);
fallingEntityKillers.add(Material.ZOMBIE_WALL_HEAD);
fallingEntityKillers.add(Material.SKELETON_SKULL);
fallingEntityKillers.add(Material.SKELETON_WALL_SKULL);
fallingEntityKillers.add(Material.WITHER_SKELETON_SKULL);
fallingEntityKillers.add(Material.WITHER_SKELETON_WALL_SKULL);
// Crop Blocks
cropBlocks = EnumSet.noneOf(Material.class);
cropBlocks.add(Material.WHEAT);
cropBlocks.add(Material.MELON_STEM);
cropBlocks.add(Material.PUMPKIN_STEM);
cropBlocks.add(Material.CARROT);
cropBlocks.add(Material.POTATO);
cropBlocks.add(Material.BEETROOT);
// Container Blocks
containerBlocks = EnumSet.noneOf(Material.class);
containerBlocks.add(Material.CHEST);
containerBlocks.add(Material.TRAPPED_CHEST);
containerBlocks.add(Material.DISPENSER);
containerBlocks.add(Material.DROPPER);
containerBlocks.add(Material.HOPPER);
containerBlocks.add(Material.BREWING_STAND);
containerBlocks.add(Material.FURNACE);
containerBlocks.add(Material.BEACON);
containerBlocks.add(Material.SHULKER_BOX);
containerBlocks.add(Material.BLACK_SHULKER_BOX);
containerBlocks.add(Material.BLUE_SHULKER_BOX);
containerBlocks.add(Material.LIGHT_GRAY_SHULKER_BOX);
containerBlocks.add(Material.BROWN_SHULKER_BOX);
containerBlocks.add(Material.CYAN_SHULKER_BOX);
containerBlocks.add(Material.GRAY_SHULKER_BOX);
containerBlocks.add(Material.GREEN_SHULKER_BOX);
containerBlocks.add(Material.LIGHT_BLUE_SHULKER_BOX);
containerBlocks.add(Material.MAGENTA_SHULKER_BOX);
containerBlocks.add(Material.LIME_SHULKER_BOX);
containerBlocks.add(Material.ORANGE_SHULKER_BOX);
containerBlocks.add(Material.PINK_SHULKER_BOX);
containerBlocks.add(Material.PURPLE_SHULKER_BOX);
containerBlocks.add(Material.RED_SHULKER_BOX);
containerBlocks.add(Material.WHITE_SHULKER_BOX);
containerBlocks.add(Material.YELLOW_SHULKER_BOX);
// Doesn't actually have a block inventory
// containerBlocks.add(Material.ENDER_CHEST);
// It doesn't seem like you could injure people with some of these, but they exist, so....
projectileItems = new EnumMap<EntityType, Material>(EntityType.class);
projectileItems.put(EntityType.ARROW, Material.ARROW);
projectileItems.put(EntityType.EGG, Material.EGG);
projectileItems.put(EntityType.ENDER_PEARL, Material.ENDER_PEARL);
projectileItems.put(EntityType.SMALL_FIREBALL, Material.FIRE_CHARGE); // Fire charge
projectileItems.put(EntityType.FIREBALL, Material.FIRE_CHARGE); // Fire charge
projectileItems.put(EntityType.FISHING_HOOK, Material.FISHING_ROD);
projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL);
projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION);
projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE);
projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL);
nonFluidProofBlocks = EnumSet.noneOf(Material.class);
nonFluidProofBlocks.addAll(singleBlockPlants);
nonFluidProofBlocks.addAll(doublePlants);
nonFluidProofBlocks.add(Material.REDSTONE_WALL_TORCH);
nonFluidProofBlocks.add(Material.LEVER);
nonFluidProofBlocks.add(Material.WALL_TORCH);
nonFluidProofBlocks.add(Material.TRIPWIRE_HOOK);
nonFluidProofBlocks.add(Material.COCOA);
nonFluidProofBlocks.addAll(pressurePlates);
nonFluidProofBlocks.addAll(saplings);
nonFluidProofBlocks.add(Material.WHEAT);
nonFluidProofBlocks.add(Material.CARROT);
nonFluidProofBlocks.add(Material.POTATO);
nonFluidProofBlocks.add(Material.BEETROOT);
nonFluidProofBlocks.add(Material.NETHER_WART);
nonFluidProofBlocks.add(Material.TORCH);
nonFluidProofBlocks.add(Material.FLOWER_POT);
nonFluidProofBlocks.add(Material.POWERED_RAIL);
nonFluidProofBlocks.add(Material.DETECTOR_RAIL);
nonFluidProofBlocks.add(Material.ACTIVATOR_RAIL);
nonFluidProofBlocks.add(Material.RAIL);
nonFluidProofBlocks.add(Material.LEVER);
nonFluidProofBlocks.add(Material.REDSTONE_WIRE);
nonFluidProofBlocks.add(Material.REDSTONE_TORCH);
nonFluidProofBlocks.add(Material.REPEATER);
nonFluidProofBlocks.add(Material.COMPARATOR);
nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR);
nonFluidProofBlocks.addAll(carpets);
bedBlocks = EnumSet.noneOf(Material.class);
bedBlocks.add(Material.BLACK_BED);
bedBlocks.add(Material.BLUE_BED);
bedBlocks.add(Material.LIGHT_GRAY_BED);
bedBlocks.add(Material.BROWN_BED);
bedBlocks.add(Material.CYAN_BED);
bedBlocks.add(Material.GRAY_BED);
bedBlocks.add(Material.GREEN_BED);
bedBlocks.add(Material.LIGHT_BLUE_BED);
bedBlocks.add(Material.MAGENTA_BED);
bedBlocks.add(Material.LIME_BED);
bedBlocks.add(Material.ORANGE_BED);
bedBlocks.add(Material.PINK_BED);
bedBlocks.add(Material.PURPLE_BED);
bedBlocks.add(Material.RED_BED);
bedBlocks.add(Material.WHITE_BED);
bedBlocks.add(Material.YELLOW_BED);
concreteBlocks = EnumSet.noneOf(Material.class);
concreteBlocks.add(Material.BLACK_CONCRETE);
concreteBlocks.add(Material.BLUE_CONCRETE);
concreteBlocks.add(Material.LIGHT_GRAY_CONCRETE);
concreteBlocks.add(Material.BROWN_CONCRETE);
concreteBlocks.add(Material.CYAN_CONCRETE);
concreteBlocks.add(Material.GRAY_CONCRETE);
concreteBlocks.add(Material.GREEN_CONCRETE);
concreteBlocks.add(Material.LIGHT_BLUE_CONCRETE);
concreteBlocks.add(Material.MAGENTA_CONCRETE);
concreteBlocks.add(Material.LIME_CONCRETE);
concreteBlocks.add(Material.ORANGE_CONCRETE);
concreteBlocks.add(Material.PINK_CONCRETE);
concreteBlocks.add(Material.PURPLE_CONCRETE);
concreteBlocks.add(Material.RED_CONCRETE);
concreteBlocks.add(Material.WHITE_CONCRETE);
concreteBlocks.add(Material.YELLOW_CONCRETE);
}
private static final BlockFace[] relativeBlockFaces = new BlockFace[]{
BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN
};
/**
* Returns a list of block locations around the block that are of the type specified by the integer list parameter
*
* @param block The central block to get the blocks around
* @param type The type of blocks around the center block to return
* @return List of block locations around the block that are of the type specified by the integer list parameter
*/
public static List<Location> getBlocksNearby(org.bukkit.block.Block block, Set<Material> type) {
ArrayList<Location> blocks = new ArrayList<Location>();
for (BlockFace blockFace : relativeBlockFaces) {
if (type.contains(block.getRelative(blockFace).getType())) {
blocks.add(block.getRelative(blockFace).getLocation());
}
}
return blocks;
}
public static boolean isTop(BlockData data) {
if (data instanceof Bisected && !(data instanceof Stairs)) {
return ((Bisected) data).getHalf() == Half.TOP;
}
return false;
}
public static Material getInventoryHolderType(InventoryHolder holder) {
if (holder instanceof DoubleChest) {
return getInventoryHolderType(((DoubleChest) holder).getLeftSide());
} else if (holder instanceof BlockState) {
return ((BlockState) holder).getType();
} else {
return null;
}
}
public static Location getInventoryHolderLocation(InventoryHolder holder) {
if (holder instanceof DoubleChest) {
return getInventoryHolderLocation(((DoubleChest) holder).getLeftSide());
} else if (holder instanceof BlockState) {
return ((BlockState) holder).getLocation();
} else {
return null;
}
}
public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] items2) {
final ArrayList<ItemStack> diff = new ArrayList<ItemStack>();
for (ItemStack current : items2) {
diff.add(new ItemStack(current));
}
for (ItemStack previous : items1) {
boolean found = false;
for (ItemStack current : diff) {
if (current.isSimilar(previous)) {
int newAmount = current.getAmount() - previous.getAmount();
if (newAmount == 0) {
diff.remove(current);
} else {
current.setAmount(newAmount);
}
found = true;
break;
}
}
if (!found) {
ItemStack subtracted = new ItemStack(previous);
subtracted.setAmount(-subtracted.getAmount());
diff.add(subtracted);
}
}
return diff.toArray(new ItemStack[diff.size()]);
}
public static ItemStack[] compressInventory(ItemStack[] items) {
final ArrayList<ItemStack> compressed = new ArrayList<ItemStack>();
for (final ItemStack item : items) {
if (item != null) {
boolean found = false;
for (final ItemStack item2 : compressed) {
if (item2.isSimilar(item)) {
item2.setAmount(item2.getAmount() + item.getAmount());
found = true;
break;
}
}
if (!found) {
compressed.add(item.clone());
}
}
}
return compressed.toArray(new ItemStack[compressed.size()]);
}
public static boolean equalTypes(int type1, int type2) {
if (type1 == type2) {
return true;
}
for (final Set<Integer> equivalent : blockEquivalents) {
if (equivalent.contains(type1) && equivalent.contains(type2)) {
return true;
}
}
return false;
}
public static String friendlyWorldname(String worldName) {
return new File(worldName).getName();
}
public static Set<Set<Integer>> getBlockEquivalents() {
return blockEquivalents;
}
public static Set<Material> getRelativeBreakables() {
return relativeBreakable;
}
public static Set<Material> getRelativeTopBreakabls() {
return relativeTopBreakable;
}
public static Set<Material> getFallingEntityKillers() {
return fallingEntityKillers;
}
public static Set<Material> getNonFluidProofBlocks() {
return nonFluidProofBlocks;
}
public static Set<Material> getCropBlocks() {
return cropBlocks;
}
public static Set<Material> getContainerBlocks() {
return containerBlocks;
}
public static boolean isConcreteBlock(Material m) {
return concreteBlocks.contains(m);
}
public static String entityName(Entity entity) {
if (entity instanceof Player) {
return ((Player) entity).getName();
}
if (entity instanceof TNTPrimed) {
return "TNT";
}
return entity.getClass().getSimpleName().substring(5);
}
public static void giveTool(Player player, Material type) {
final Inventory inv = player.getInventory();
if (inv.contains(type)) {
player.sendMessage(ChatColor.RED + "You have already a " + type.name());
} else {
final int free = inv.firstEmpty();
if (free >= 0) {
if (player.getInventory().getItemInMainHand() != null && player.getInventory().getItemInMainHand().getType() != Material.AIR) {
inv.setItem(free, player.getInventory().getItemInMainHand());
}
player.getInventory().setItemInMainHand(new ItemStack(type));
player.sendMessage(ChatColor.GREEN + "Here's your " + type.name());
} else {
player.sendMessage(ChatColor.RED + "You have no empty slot in your inventory");
}
}
}
public static int saveSpawnHeight(Location loc) {
final World world = loc.getWorld();
final Chunk chunk = world.getChunkAt(loc);
if (!world.isChunkLoaded(chunk)) {
world.loadChunk(chunk);
}
final int x = loc.getBlockX(), z = loc.getBlockZ();
int y = loc.getBlockY();
boolean lower = world.getBlockAt(x, y, z).isEmpty(), upper = world.getBlockAt(x, y + 1, z).isEmpty();
while ((!lower || !upper) && y != 127) {
lower = upper;
upper = world.getBlockAt(x, ++y, z).isEmpty();
}
while (world.getBlockAt(x, y - 1, z).isEmpty() && y != 0) {
y--;
}
return y;
}
public static int modifyContainer(BlockState b, ItemStack item, boolean remove) {
if (b instanceof InventoryHolder) {
final Inventory inv = ((InventoryHolder) b).getInventory();
if (remove) {
final ItemStack tmp = inv.removeItem(item).get(0);
return tmp != null ? tmp.getAmount() : 0;
} else if (item.getAmount() > 0) {
final ItemStack tmp = inv.addItem(item).get(0);
return tmp != null ? tmp.getAmount() : 0;
}
}
return 0;
}
public static boolean canFallIn(World world, int x, int y, int z) {
Block block = world.getBlockAt(x, y, z);
Material mat = block.getType();
if (canDirectlyFallIn(mat)) {
return true;
} else if (getFallingEntityKillers().contains(mat) || singleBlockPlants.contains(mat) || mat == Material.VINE) {
if (slabs.contains(mat)) {
if (((Slab) block.getBlockData()).getType() != Type.BOTTOM) {
return false;
}
}
return true;
}
return false;
}
public static boolean canDirectlyFallIn(Material m) {
return isEmpty(m) || m == Material.WATER || m == Material.LAVA || m == Material.FIRE;
}
public static Material itemIDfromProjectileEntity(Entity e) {
return projectileItems.get(e.getType());
}
public static boolean isDoublePlant(Material m) {
return doublePlants.contains(m);
}
public static boolean isWoodenDoor(Material m) {
return woodenDoors.contains(m);
}
public static boolean isButton(Material m) {
return buttons.contains(m);
}
public static boolean isEmpty(Material m) {
return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR;
}
public static String toString(ItemStack stack) {
if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) {
return "nothing";
}
StringBuilder sb = new StringBuilder();
sb.append(stack.getAmount()).append("x ").append(stack.getType().name());
ItemMeta meta = stack.getItemMeta();
boolean metaStarted = false;
if (meta.hasEnchants()) {
Map<Enchantment, Integer> enchants = meta.getEnchants();
if (!enchants.isEmpty()) {
for (Entry<Enchantment, Integer> e : enchants.entrySet()) {
if (!metaStarted) {
sb.append(" [");
metaStarted = true;
} else {
sb.append(", ");
}
sb.append(formatMinecraftKey(e.getKey().getKey().getKey()));
if (e.getValue().intValue() > 1) {
sb.append(" ").append(maybeToRoman(e.getValue().intValue() - 1));
}
}
}
}
if (meta instanceof EnchantmentStorageMeta) {
EnchantmentStorageMeta emeta = (EnchantmentStorageMeta) meta;
if (emeta.hasStoredEnchants()) {
Map<Enchantment, Integer> enchants = emeta.getStoredEnchants();
if (!enchants.isEmpty()) {
for (Entry<Enchantment, Integer> e : enchants.entrySet()) {
if (!metaStarted) {
sb.append(" [");
metaStarted = true;
} else {
sb.append(", ");
}
sb.append(formatMinecraftKey(e.getKey().getKey().getKey()));
if (e.getValue().intValue() > 1) {
sb.append(" ").append(maybeToRoman(e.getValue().intValue() - 1));
}
}
}
}
}
if (metaStarted) {
sb.append("]");
}
return sb.toString();
}
private static final String[] romanNumbers = new String[] { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "XI", "X" };
private static String maybeToRoman(int value) {
if (value > 0 && value <= 10) {
return romanNumbers[value];
}
return Integer.toString(value);
}
public static String formatMinecraftKey(String s) {
char[] cap = s.toCharArray();
boolean lastSpace = true;
for (int i = 0; i < cap.length; i++) {
char c = cap[i];
if (c == '_') {
c = ' ';
lastSpace = true;
} else if (c >= '0' && c <= '9' || c == '(' || c == ')') {
lastSpace = true;
} else {
if (lastSpace) {
c = Character.toUpperCase(c);
} else {
c = Character.toLowerCase(c);
}
lastSpace = false;
}
cap[i] = c;
}
return new String(cap);
}
public static boolean isBed(Material type) {
return bedBlocks.contains(type);
}
public static Block getConnectedChest(Block chestBlock) {
// is this a chest?
BlockData blockData = chestBlock.getBlockData();
if (!(blockData instanceof org.bukkit.block.data.type.Chest)) {
return null;
}
// so check if is should have a neighbour
org.bukkit.block.data.type.Chest chestData = (org.bukkit.block.data.type.Chest) blockData;
org.bukkit.block.data.type.Chest.Type chestType = chestData.getType();
if (chestType != org.bukkit.block.data.type.Chest.Type.SINGLE) {
// check if the neighbour exists
BlockFace chestFace = chestData.getFacing();
BlockFace faceToSecondChest;
if (chestFace == BlockFace.WEST) {
faceToSecondChest = BlockFace.NORTH;
} else if (chestFace == BlockFace.NORTH) {
faceToSecondChest = BlockFace.EAST;
} else if (chestFace == BlockFace.EAST) {
faceToSecondChest = BlockFace.SOUTH;
} else if (chestFace == BlockFace.SOUTH) {
faceToSecondChest = BlockFace.WEST;
} else {
return null;
}
org.bukkit.block.data.type.Chest.Type wantedChestType = org.bukkit.block.data.type.Chest.Type.RIGHT;
if (chestType == org.bukkit.block.data.type.Chest.Type.RIGHT) {
faceToSecondChest = faceToSecondChest.getOppositeFace();
wantedChestType = org.bukkit.block.data.type.Chest.Type.LEFT;
}
Block face = chestBlock.getRelative(faceToSecondChest);
if (face.getType() == chestBlock.getType()) {
// check is the neighbour connects to this chest
org.bukkit.block.data.type.Chest otherChestData = (org.bukkit.block.data.type.Chest) face.getBlockData();
if(otherChestData.getType() != wantedChestType || otherChestData.getFacing() != chestFace) {
return null;
}
return face;
}
}
return null;
}
public static Entity loadEntityAround(Chunk chunk, UUID uuid) {
Entity e = Bukkit.getEntity(uuid);
if (e != null) {
return e;
}
if (!chunk.isLoaded()) {
chunk.load();
e = Bukkit.getEntity(uuid);
if (e != null) {
return e;
}
}
int chunkx = chunk.getX();
int chunkz = chunk.getZ();
for (int i = 0; i < 8; i++) {
int x = i < 3 ? chunkx - 1 : (i < 5 ? chunkx : chunkx + 1);
int z = i == 0 || i == 3 || i == 5 ? chunkz - 1 : (i == 1 || i == 6 ? chunkz : chunkz + 1);
if (!chunk.getWorld().isChunkLoaded(x, z)) {
chunk.getWorld().loadChunk(x, z);
e = Bukkit.getEntity(uuid);
if (e != null) {
return e;
}
}
}
return null;
}
private static final HashMap<String, EntityType> types = new HashMap<>();
static {
for (EntityType t : EntityType.values()) {
types.put(t.name().toLowerCase(), t);
@SuppressWarnings("deprecation")
String typeName = t.getName();
if (typeName != null) {
types.put(typeName.toLowerCase(), t);
}
Class<? extends Entity> ec = t.getEntityClass();
if (ec != null) {
types.put(ec.getSimpleName().toLowerCase(), t);
}
}
}
public static EntityType matchEntityType(String typeName) {
return types.get(typeName.toLowerCase());
}
public static ItemStack getItemInSlot(ArmorStand stand, EquipmentSlot slot) {
if (slot == EquipmentSlot.HAND) {
return stand.getEquipment().getItemInMainHand();
} else if (slot == EquipmentSlot.OFF_HAND) {
return stand.getEquipment().getItemInOffHand();
} else if (slot == EquipmentSlot.FEET) {
return stand.getEquipment().getBoots();
} else if (slot == EquipmentSlot.LEGS) {
return stand.getEquipment().getLeggings();
} else if (slot == EquipmentSlot.CHEST) {
return stand.getEquipment().getChestplate();
} else if (slot == EquipmentSlot.HEAD) {
return stand.getEquipment().getHelmet();
}
return null;
}
public static void setItemInSlot(ArmorStand stand, EquipmentSlot slot, ItemStack stack) {
if (slot == EquipmentSlot.HAND) {
stand.getEquipment().setItemInMainHand(stack);
} else if (slot == EquipmentSlot.OFF_HAND) {
stand.getEquipment().setItemInOffHand(stack);
} else if (slot == EquipmentSlot.FEET) {
stand.getEquipment().setBoots(stack);
} else if (slot == EquipmentSlot.LEGS) {
stand.getEquipment().setLeggings(stack);
} else if (slot == EquipmentSlot.CHEST) {
stand.getEquipment().setChestplate(stack);
} else if (slot == EquipmentSlot.HEAD) {
stand.getEquipment().setHelmet(stack);
}
}
public static ItemStack[] deepCopy(ItemStack[] of) {
ItemStack[] result = new ItemStack[of.length];
for (int i = 0; i < result.length; i++) {
result[i] = of[i] == null ? null : new ItemStack(of[i]);
}
return result;
}
private static int getFirstPartialItemStack(ItemStack item, ItemStack[] contents, int start) {
for (int i = start; i < contents.length; i++) {
ItemStack content = contents[i];
if (content != null && content.isSimilar(item) && content.getAmount() < content.getMaxStackSize()) {
return i;
}
}
return -1;
}
private static int getFirstFreeItemStack(ItemStack[] contents, int start) {
for (int i = start; i < contents.length; i++) {
ItemStack content = contents[i];
if (content == null || content.getAmount() == 0 || content.getType() == Material.AIR) {
return i;
}
}
return -1;
}
public static boolean hasInventoryStorageSpaceFor(Inventory inv, ItemStack... items) {
ItemStack[] contents = deepCopy(inv.getStorageContents());
for (ItemStack item : items) {
if (item != null && item.getType() != Material.AIR) {
int remaining = item.getAmount();
// fill partial stacks
int firstPartial = -1;
while (remaining > 0) {
firstPartial = getFirstPartialItemStack(item, contents, firstPartial + 1);
if (firstPartial < 0) {
break;
}
ItemStack content = contents[firstPartial];
int add = Math.min(content.getMaxStackSize() - content.getAmount(), remaining);
content.setAmount(content.getAmount() + add);
remaining -= add;
}
// create new stacks
int firstFree = -1;
while (remaining > 0) {
firstFree = getFirstFreeItemStack(contents, firstFree + 1);
if (firstFree < 0) {
return false; // no free place found
}
ItemStack content = new ItemStack(item);
contents[firstFree] = content;
// max stack size might return -1, in this case assume 1
int add = Math.min(Math.max(content.getMaxStackSize(), 1), remaining);
content.setAmount(add);
remaining -= add;
}
}
}
return true;
}
}

View File

@ -1,210 +0,0 @@
package de.diddiz.util;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.Consumer;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import java.util.List;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import static de.diddiz.LogBlock.config.Config.mb4;
public class LoggingUtil {
public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState replaced, BlockState placed) {
Location loc = replaced.getLocation();
if (!placed.getType().hasGravity() || !BukkitUtils.canDirectlyFallIn(replaced.getBlock().getRelative(BlockFace.DOWN).getType())) {
if (BukkitUtils.isEmpty(replaced.getType())) {
consumer.queueBlockPlace(actor, placed);
} else {
consumer.queueBlockReplace(actor, replaced, placed);
}
return;
}
int x = loc.getBlockX();
int initialy = loc.getBlockY();
int y = initialy;
int z = loc.getBlockZ();
while (y > 0 && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) {
y--;
}
if (initialy != y && !BukkitUtils.isEmpty(replaced.getType())) {
// this is not the final location but the block got removed (vines etc)
consumer.queueBlockBreak(actor, replaced);
}
// If y is 0 then the block fell out of the world :(
if (y != 0) {
// Run this check to avoid false positives
Location finalLoc = new Location(loc.getWorld(), x, y, z);
if (y == initialy || !BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) {
if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) {
consumer.queueBlockPlace(actor, finalLoc, placed.getBlockData());
} else {
consumer.queueBlockReplace(actor, finalLoc.getBlock().getState(), placed.getBlockData());
}
}
}
}
public static void smartLogFallables(Consumer consumer, Actor actor, Block origin) {
WorldConfig wcfg = getWorldConfig(origin.getWorld());
if (wcfg == null) {
return;
}
//Handle falling blocks
Block checkBlock = origin.getRelative(BlockFace.UP);
int up = 0;
final int highestBlock = checkBlock.getWorld().getHighestBlockYAt(checkBlock.getLocation());
while (checkBlock.getType().hasGravity()) {
// Record this block as falling
consumer.queueBlockBreak(actor, checkBlock.getState());
// Guess where the block is going (This could be thrown of by explosions, but it is better than nothing)
Location loc = origin.getLocation();
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
while (y > 0 && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) {
y--;
}
// If y is 0 then the sand block fell out of the world :(
if (y != 0) {
Location finalLoc = new Location(loc.getWorld(), x, y, z);
// Run this check to avoid false positives
if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) {
finalLoc.add(0, up, 0); // Add this here after checking for block breakers
if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) {
consumer.queueBlockPlace(actor, finalLoc, checkBlock.getBlockData());
} else {
consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getBlockData(), checkBlock.getBlockData());
}
up++;
}
}
if (checkBlock.getY() >= highestBlock) {
break;
}
checkBlock = checkBlock.getRelative(BlockFace.UP);
}
}
public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block origin) {
smartLogBlockReplace(consumer, actor, origin, null);
}
public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block origin, BlockData replacedWith) {
WorldConfig wcfg = getWorldConfig(origin.getWorld());
if (wcfg == null) {
return;
}
Block checkBlock = origin.getRelative(BlockFace.UP);
if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) {
if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN) {
consumer.queueSignBreak(actor, (Sign) checkBlock.getState());
} else if (checkBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(checkBlock.getType())) {
Block doorBlock = checkBlock;
// If the doorBlock is the top half a door the player simply punched a door
// this will be handled later.
if (!BukkitUtils.isTop(doorBlock.getBlockData())) {
doorBlock = doorBlock.getRelative(BlockFace.UP);
// Fall back check just in case the top half wasn't a door
if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) {
consumer.queueBlockBreak(actor, doorBlock.getState());
}
consumer.queueBlockBreak(actor, checkBlock.getState());
}
} else if (BukkitUtils.isDoublePlant(checkBlock.getType())) {
Block plantBlock = checkBlock;
// If the plantBlock is the top half of a double plant the player simply
// punched the plant this will be handled later.
if (!BukkitUtils.isTop(plantBlock.getBlockData())) {
plantBlock = plantBlock.getRelative(BlockFace.UP);
// Fall back check just in case the top half wasn't a plant
if (BukkitUtils.isDoublePlant(plantBlock.getType())) {
consumer.queueBlockBreak(actor, plantBlock.getState());
}
consumer.queueBlockBreak(actor, checkBlock.getState());
}
} else {
consumer.queueBlockBreak(actor, checkBlock.getState());
}
}
List<Location> relativeBreakables = BukkitUtils.getBlocksNearby(origin, BukkitUtils.getRelativeBreakables());
if (relativeBreakables.size() != 0) {
for (Location location : relativeBreakables) {
Block block = location.getBlock();
BlockData blockData = block.getBlockData();
if (blockData instanceof Directional) {
if (block.getRelative(((Directional) blockData).getFacing().getOppositeFace()).equals(origin)) {
if (wcfg.isLogging(Logging.SIGNTEXT) && block.getType() == Material.WALL_SIGN) {
consumer.queueSignBreak(actor, (Sign) block.getState());
} else {
consumer.queueBlockBreak(actor, block.getState());
}
}
}
}
}
// Special door check
if (origin.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(origin.getType())) {
Block doorBlock = origin;
// Up or down?
if (!BukkitUtils.isTop(doorBlock.getBlockData())) {
doorBlock = doorBlock.getRelative(BlockFace.UP);
} else {
doorBlock = doorBlock.getRelative(BlockFace.DOWN);
}
if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) {
consumer.queueBlockBreak(actor, doorBlock.getState());
}
} else if (BukkitUtils.isDoublePlant(origin.getType())) { // Special double plant check
Block plantBlock = origin;
// Up or down?
if (!BukkitUtils.isTop(origin.getBlockData())) {
plantBlock = plantBlock.getRelative(BlockFace.UP);
} else {
plantBlock = plantBlock.getRelative(BlockFace.DOWN);
}
if (BukkitUtils.isDoublePlant(plantBlock.getType())) {
consumer.queueBlockBreak(actor, plantBlock.getState());
}
}
// Do this down here so that the block is added after blocks sitting on it
if (replacedWith == null) {
consumer.queueBlockBreak(actor, origin.getState());
} else {
consumer.queueBlockReplace(actor, origin.getState(), replacedWith);
}
}
public static String checkText(String text) {
if (text == null) {
return text;
}
if (mb4) {
return text;
}
return text.replaceAll("[^\\u0000-\\uFFFF]", "?");
}
}

View File

@ -1,92 +0,0 @@
package de.diddiz.worldedit;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.BlockVector;
public class CuboidRegion implements Cloneable {
private World world;
private BlockVector min = new BlockVector();
private BlockVector max = new BlockVector();
public CuboidRegion(World world, BlockVector first, BlockVector second) {
this.world = world;
this.min.setX(Math.min(first.getBlockX(),second.getBlockX()));
this.min.setY(Math.min(first.getBlockY(),second.getBlockY()));
this.min.setZ(Math.min(first.getBlockZ(),second.getBlockZ()));
this.max.setX(Math.max(first.getBlockX(),second.getBlockX()));
this.max.setY(Math.max(first.getBlockY(),second.getBlockY()));
this.max.setZ(Math.max(first.getBlockZ(),second.getBlockZ()));
}
public static CuboidRegion fromPlayerSelection(Player player) {
Plugin worldEditPlugin = player.getServer().getPluginManager().getPlugin("WorldEdit");
LocalSession session = ((WorldEditPlugin) worldEditPlugin).getSession(player);
World world = player.getWorld();
com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world);
if (!weWorld.equals(session.getSelectionWorld())) {
throw new IllegalArgumentException("No selection defined");
}
Region selection;
try {
selection = session.getSelection(weWorld);
} catch (IncompleteRegionException e) {
throw new IllegalArgumentException("No selection defined");
}
if (selection == null) {
throw new IllegalArgumentException("No selection defined");
}
if (!(selection instanceof com.sk89q.worldedit.regions.CuboidRegion)) {
throw new IllegalArgumentException("You have to define a cuboid selection");
}
BlockVector3 min = selection.getMinimumPoint();
BlockVector3 max = selection.getMaximumPoint();
return new CuboidRegion(world, new BlockVector(min.getBlockX(), min.getBlockY(), min.getBlockZ()), new BlockVector(max.getBlockX(), max.getBlockY(), max.getBlockZ()));
}
public static CuboidRegion fromCorners(World world, Location first, Location second) {
return new CuboidRegion(world, new BlockVector(first.getBlockX(), first.getBlockY(), first.getBlockZ()), new BlockVector(second.getBlockX(), second.getBlockY(), second.getBlockZ()));
}
public World getWorld() {
return world;
}
public BlockVector getMinimumPoint() {
return min;
}
public BlockVector getMaximumPoint() {
return max;
}
public int getSizeX() {
return max.getBlockX() - min.getBlockX() + 1;
}
public int getSizeZ() {
return max.getBlockZ() - min.getBlockZ() + 1;
}
@Override
public CuboidRegion clone() {
try {
CuboidRegion clone = (CuboidRegion) super.clone();
clone.min = min.clone();
clone.max = max.clone();
return clone;
} catch (final CloneNotSupportedException ex) {
throw new Error("CuboidRegion should be cloneable", ex);
}
}
}

View File

@ -309,7 +309,7 @@
43:13,minecraft:stone_brick_slab[type=double,waterlogged=false]
43:14,minecraft:nether_brick_slab[type=double,waterlogged=false]
43:15,minecraft:smooth_quartz
44:0,minecraft:stone_slab[type=bottom,waterlogged=false]
44:0,minecraft:smooth_stone_slab[type=bottom,waterlogged=false]
44:1,minecraft:sandstone_slab[type=bottom,waterlogged=false]
44:2,minecraft:petrified_oak_slab[type=bottom,waterlogged=false]
44:3,minecraft:cobblestone_slab[type=bottom,waterlogged=false]
@ -317,7 +317,7 @@
44:5,minecraft:stone_brick_slab[type=bottom,waterlogged=false]
44:6,minecraft:nether_brick_slab[type=bottom,waterlogged=false]
44:7,minecraft:quartz_slab[type=bottom,waterlogged=false]
44:8,minecraft:stone_slab[type=top,waterlogged=false]
44:8,minecraft:smooth_stone_slab[type=top,waterlogged=false]
44:9,minecraft:sandstone_slab[type=top,waterlogged=false]
44:10,minecraft:petrified_oak_slab[type=top,waterlogged=false]
44:11,minecraft:cobblestone_slab[type=top,waterlogged=false]
@ -440,22 +440,22 @@
62:10,minecraft:furnace[facing=west,lit=false]
62:11,minecraft:furnace[facing=east,lit=false]
62:15,minecraft:furnace[facing=south,lit=false]
63:0,minecraft:sign[rotation=0,waterlogged=false]
63:1,minecraft:sign[rotation=1,waterlogged=false]
63:2,minecraft:sign[rotation=2,waterlogged=false]
63:3,minecraft:sign[rotation=3,waterlogged=false]
63:4,minecraft:sign[rotation=4,waterlogged=false]
63:5,minecraft:sign[rotation=5,waterlogged=false]
63:6,minecraft:sign[rotation=6,waterlogged=false]
63:7,minecraft:sign[rotation=7,waterlogged=false]
63:8,minecraft:sign[rotation=8,waterlogged=false]
63:9,minecraft:sign[rotation=9,waterlogged=false]
63:10,minecraft:sign[rotation=10,waterlogged=false]
63:11,minecraft:sign[rotation=11,waterlogged=false]
63:12,minecraft:sign[rotation=12,waterlogged=false]
63:13,minecraft:sign[rotation=13,waterlogged=false]
63:14,minecraft:sign[rotation=14,waterlogged=false]
63:15,minecraft:sign[rotation=15,waterlogged=false]
63:0,minecraft:oak_sign[rotation=0,waterlogged=false]
63:1,minecraft:oak_sign[rotation=1,waterlogged=false]
63:2,minecraft:oak_sign[rotation=2,waterlogged=false]
63:3,minecraft:oak_sign[rotation=3,waterlogged=false]
63:4,minecraft:oak_sign[rotation=4,waterlogged=false]
63:5,minecraft:oak_sign[rotation=5,waterlogged=false]
63:6,minecraft:oak_sign[rotation=6,waterlogged=false]
63:7,minecraft:oak_sign[rotation=7,waterlogged=false]
63:8,minecraft:oak_sign[rotation=8,waterlogged=false]
63:9,minecraft:oak_sign[rotation=9,waterlogged=false]
63:10,minecraft:oak_sign[rotation=10,waterlogged=false]
63:11,minecraft:oak_sign[rotation=11,waterlogged=false]
63:12,minecraft:oak_sign[rotation=12,waterlogged=false]
63:13,minecraft:oak_sign[rotation=13,waterlogged=false]
63:14,minecraft:oak_sign[rotation=14,waterlogged=false]
63:15,minecraft:oak_sign[rotation=15,waterlogged=false]
64:0,minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=false]
64:1,minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=false]
64:2,minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=false]
@ -496,14 +496,14 @@
67:13,minecraft:cobblestone_stairs[facing=west,half=top,shape=straight,waterlogged=false]
67:14,minecraft:cobblestone_stairs[facing=south,half=top,shape=straight,waterlogged=false]
67:15,minecraft:cobblestone_stairs[facing=north,half=top,shape=straight,waterlogged=false]
68:0,minecraft:wall_sign[facing=north,waterlogged=false]
68:3,minecraft:wall_sign[facing=south,waterlogged=false]
68:4,minecraft:wall_sign[facing=west,waterlogged=false]
68:5,minecraft:wall_sign[facing=east,waterlogged=false]
68:9,minecraft:wall_sign[facing=south,waterlogged=false]
68:10,minecraft:wall_sign[facing=west,waterlogged=false]
68:11,minecraft:wall_sign[facing=east,waterlogged=false]
68:15,minecraft:wall_sign[facing=south,waterlogged=false]
68:0,minecraft:oak_wall_sign[facing=north,waterlogged=false]
68:3,minecraft:oak_wall_sign[facing=south,waterlogged=false]
68:4,minecraft:oak_wall_sign[facing=west,waterlogged=false]
68:5,minecraft:oak_wall_sign[facing=east,waterlogged=false]
68:9,minecraft:oak_wall_sign[facing=south,waterlogged=false]
68:10,minecraft:oak_wall_sign[facing=west,waterlogged=false]
68:11,minecraft:oak_wall_sign[facing=east,waterlogged=false]
68:15,minecraft:oak_wall_sign[facing=south,waterlogged=false]
69:0,minecraft:lever[face=ceiling,facing=west,powered=false]
69:1,minecraft:lever[face=wall,facing=east,powered=false]
69:2,minecraft:lever[face=wall,facing=west,powered=false]
@ -919,10 +919,10 @@
115:15,minecraft:air
116:0,minecraft:enchanting_table
117:0,minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]
118:0,minecraft:cauldron[level=0]
118:1,minecraft:cauldron[level=1]
118:2,minecraft:cauldron[level=2]
118:3,minecraft:cauldron[level=3]
118:0,minecraft:cauldron
118:1,minecraft:cauldron
118:2,minecraft:cauldron
118:3,minecraft:cauldron
118:4,minecraft:air
118:5,minecraft:air
118:6,minecraft:air
@ -1113,8 +1113,8 @@
137:14,minecraft:command_block[conditional=true,facing=down]
137:15,minecraft:command_block[conditional=true,facing=up]
138:0,minecraft:beacon
139:0,minecraft:cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false]
139:1,minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false]
139:0,minecraft:cobblestone_wall[east=none,north=none,south=none,up=false,waterlogged=false,west=none]
139:1,minecraft:mossy_cobblestone_wall[east=none,north=none,south=none,up=false,waterlogged=false,west=none]
140:0,minecraft:flower_pot
141:0,minecraft:carrots[age=0]
141:1,minecraft:carrots[age=1]
@ -1813,7 +1813,7 @@
207:13,minecraft:air
207:14,minecraft:air
207:15,minecraft:air
208:0,minecraft:grass_path
208:0,minecraft:dirt_path
209:0,minecraft:end_gateway
210:0,minecraft:repeating_command_block[conditional=false,facing=down]
210:1,minecraft:repeating_command_block[conditional=false,facing=up]

View File

@ -114,7 +114,7 @@
40:0,minecraft:red_mushroom
41:0,minecraft:gold_block
42:0,minecraft:iron_block
43:0,minecraft:stone_slab
43:0,minecraft:smooth_stone_slab
43:1,minecraft:sandstone_slab
43:2,minecraft:petrified_oak_slab
43:3,minecraft:cobblestone_slab
@ -171,16 +171,16 @@
62:3,minecraft:furnace
62:4,minecraft:furnace
62:5,minecraft:furnace
63:0,minecraft:sign
63:0,minecraft:oak_sign
64:0,minecraft:oak_door
65:0,minecraft:ladder
66:0,minecraft:rail
67:0,minecraft:cobblestone_stairs
68:0,minecraft:air
68:2,minecraft:wall_sign
68:3,minecraft:wall_sign
68:4,minecraft:wall_sign
68:5,minecraft:wall_sign
68:2,minecraft:oak_wall_sign
68:3,minecraft:oak_wall_sign
68:4,minecraft:oak_wall_sign
68:5,minecraft:oak_wall_sign
69:0,minecraft:lever
70:0,minecraft:stone_pressure_plate
71:0,minecraft:iron_door
@ -454,7 +454,7 @@
205:0,minecraft:purpur_slab
206:0,minecraft:end_stone_bricks
207:0,minecraft:beetroots
208:0,minecraft:grass_path
208:0,minecraft:dirt_path
209:0,minecraft:end_gateway
210:0,minecraft:repeating_command_block
211:0,minecraft:chain_command_block
@ -599,7 +599,7 @@
321:0,minecraft:painting
322:0,minecraft:golden_apple
322:1,minecraft:enchanted_golden_apple
323:0,minecraft:sign
323:0,minecraft:oak_sign
324:0,minecraft:oak_door
325:0,minecraft:bucket
326:0,minecraft:water_bucket
@ -632,8 +632,8 @@
350:0,minecraft:cooked_cod
350:1,minecraft:cooked_salmon
351:0,minecraft:ink_sac
351:1,minecraft:rose_red
351:2,minecraft:cactus_green
351:1,minecraft:red_dye
351:2,minecraft:green_dye
351:3,minecraft:cocoa_beans
351:4,minecraft:lapis_lazuli
351:5,minecraft:purple_dye
@ -642,7 +642,7 @@
351:8,minecraft:gray_dye
351:9,minecraft:pink_dye
351:10,minecraft:lime_dye
351:11,minecraft:dandelion_yellow
351:11,minecraft:yellow_dye
351:12,minecraft:light_blue_dye
351:13,minecraft:magenta_dye
351:14,minecraft:orange_dye

View File

@ -5,8 +5,8 @@ authors: [md_5, ammar2, frymaster]
website: http://dev.bukkit.org/server-mods/logblock/
main: de.diddiz.LogBlock.LogBlock
description: ${project.description}
softdepend: [WorldEdit]
api-version: 1.13
softdepend: [WorldEdit, WorldGuard]
api-version: 1.20
commands:
lb:
description: 'LogBlock plugin commands'

View File

@ -1,10 +1,8 @@
package de.diddiz.LogBlock;
import de.diddiz.util.Utils;
import org.junit.Assert;
import org.junit.Test;
import de.diddiz.LogBlock.util.Utils;
import java.util.Arrays;
import java.util.List;