Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1832d04a8 | ||
|
|
dd2701c6b5 | ||
|
|
eac043ec1d | ||
|
|
111b930ea9 | ||
|
|
d200fd356a | ||
|
|
ec7b60d017 | ||
|
|
85fc7ae87f | ||
|
|
61496e1979 | ||
|
|
d419acf751 | ||
|
|
3c0ef4cdd4 | ||
|
|
eb376a8633 | ||
|
|
c2c3d5affc | ||
|
|
8767153930 | ||
|
|
ae26a331d5 | ||
|
|
3f4e3152ae | ||
|
|
265362037c | ||
|
|
cdb05c75ec | ||
|
|
9e64acd6f1 | ||
|
|
9125e37d8c | ||
|
|
080ff8e58c | ||
|
|
5a453b2ed8 | ||
|
|
614088e75b | ||
|
|
50d3903c19 | ||
|
|
5931893f28 | ||
|
|
d6e398a309 | ||
|
|
9223431c96 | ||
|
|
4d8d8302a7 | ||
|
|
3b91fcc158 | ||
|
|
a108d7e13a | ||
|
|
4c61211f51 | ||
|
|
33add0491e | ||
|
|
5468d12b5d | ||
|
|
901eb1317f | ||
|
|
806d94070d | ||
|
|
13b1428aad | ||
|
|
6ceb63af9f | ||
|
|
f13ef25335 | ||
|
|
b7a3f5671e | ||
|
|
7b16512907 | ||
|
|
4e55c09912 | ||
|
|
561d8794e3 | ||
|
|
cfe75015d7 | ||
|
|
afb1e70fb6 | ||
|
|
1784d609b0 | ||
|
|
e4967f711d | ||
|
|
a425393d8a | ||
|
|
d7ef6a0c18 | ||
|
|
5df5f0a1d9 | ||
|
|
7bd5a8881f | ||
|
|
a78be7a860 | ||
|
|
31c81e68d6 | ||
|
|
ac81dd3bd8 | ||
|
|
7ec29408b1 | ||
|
|
f0d92e91d0 | ||
|
|
8fdde13fe6 | ||
|
|
89e39858e5 | ||
|
|
1f6374c9f8 | ||
|
|
5f3497ed27 | ||
|
|
2efa814ff7 | ||
|
|
65511beffe | ||
|
|
ca0f4d9a68 | ||
|
|
45ef2aecc4 | ||
|
|
0643ee0ab5 | ||
|
|
07b5f15418 | ||
|
|
0624bd8af7 | ||
|
|
70066459c5 | ||
|
|
6da18c04b8 | ||
|
|
16644cacdb | ||
|
|
3264c5b124 | ||
|
|
cd18b59e35 | ||
|
|
ac06fef951 | ||
|
|
fc25b9c27b | ||
|
|
182c7e7e50 | ||
|
|
c47e8d9851 | ||
|
|
eb8871bca2 | ||
|
|
3f634a5142 | ||
|
|
f5923dedfb | ||
|
|
0037789858 | ||
|
|
be5261a9d6 | ||
|
|
78a3cfbf09 | ||
|
|
5711d9db7f | ||
|
|
98cc72b074 | ||
|
|
d123f472af | ||
|
|
9badfea656 | ||
|
|
22dbd18ecc | ||
|
|
6d5cc52a1e | ||
|
|
7d65f459bf | ||
|
|
38a3cb1229 | ||
|
|
c27648318d | ||
|
|
c3042f5397 | ||
|
|
b78afb808f | ||
|
|
974bb42a84 | ||
|
|
1216dd2565 | ||
|
|
562d13c7d2 | ||
|
|
e28c761ab2 | ||
|
|
1165a2583f | ||
|
|
87c383b526 | ||
|
|
ed975a1e90 | ||
|
|
ceb5a4e750 | ||
|
|
132b4b6248 | ||
|
|
6d7ec368ea | ||
|
|
b138ae5f17 | ||
|
|
94e999e6cc | ||
|
|
decc71effa | ||
|
|
a3b03a9d78 | ||
|
|
8e344f4d43 | ||
|
|
a6dcfd10bb | ||
|
|
313e7e9ad3 | ||
|
|
bc24553751 | ||
|
|
aa58cc919a | ||
|
|
af1da1fcf4 | ||
|
|
176a081f6c | ||
|
|
61d3445986 | ||
|
|
52e7e167ce | ||
|
|
c2ae416c70 | ||
|
|
d407397f4a | ||
|
|
daf6dad716 | ||
|
|
60a451de97 | ||
|
|
97f10075e5 | ||
|
|
e9731a64dc | ||
|
|
abaa692f25 | ||
|
|
dcbf499a4b | ||
|
|
0ca6cac405 | ||
|
|
625cd6cbee | ||
|
|
2fa7f27110 | ||
|
|
92743bb78f | ||
|
|
c1699522be | ||
|
|
01b0b86c41 | ||
|
|
cf487aaae3 | ||
|
|
c890e33b7b | ||
|
|
9d0b683cec | ||
|
|
5eafdb5c3e | ||
|
|
24b917bf38 | ||
|
|
60df84bd9c | ||
|
|
27b8385d51 | ||
|
|
7ed0b35181 | ||
|
|
c2073ff43b | ||
|
|
abd5f66d05 | ||
|
|
55f7928357 | ||
|
|
4ff5a8b32d | ||
|
|
61db049346 | ||
|
|
8574186f40 | ||
|
|
3f87cfaf4d | ||
|
|
edbf658d13 | ||
|
|
05747e5025 | ||
|
|
e7fc2004b4 | ||
|
|
b06dea82ea | ||
|
|
227712b906 | ||
|
|
21215dbf3f | ||
|
|
f906a35a78 | ||
|
|
493e2003ea | ||
|
|
f7abb05238 | ||
|
|
da7114572b | ||
|
|
b16cf4ec6f | ||
|
|
9ffc1f39ac | ||
|
|
f2f17f30dc | ||
|
|
c497cb3189 | ||
|
|
336ce09761 | ||
|
|
59e6e58e10 | ||
|
|
3801c9f157 | ||
|
|
97831bd19b | ||
|
|
4b4405ad80 | ||
|
|
509f6601ab | ||
|
|
6acc4bcdb3 | ||
|
|
b67e9c817a | ||
|
|
7cf625c49a | ||
|
|
d76edcd5ba | ||
|
|
f6875720e1 | ||
|
|
12bb3dad81 | ||
|
|
af2b564a81 | ||
|
|
849521144e | ||
|
|
1f9ca0ee08 | ||
|
|
3e3d29a20b | ||
|
|
364d2de942 | ||
|
|
889b8734dd | ||
|
|
0997c40f57 | ||
|
|
4cceb7a48d | ||
|
|
4ec22bc42f | ||
|
|
60457e0817 | ||
|
|
b717f69bdf | ||
|
|
e9b45a387d | ||
|
|
fae8b37456 | ||
|
|
662de45731 | ||
|
|
cce14e6a45 | ||
|
|
4629e77b45 | ||
|
|
a8b115b333 | ||
|
|
0abe0a7a16 | ||
|
|
90510f61ed | ||
|
|
d8a1e4e7f5 | ||
|
|
383c77b6dd | ||
|
|
ee6fd69e6d | ||
|
|
ca96dc6fa5 | ||
|
|
417459afaf | ||
|
|
e5a91e6366 | ||
|
|
9c0cb1385e | ||
|
|
62dc4127e0 | ||
|
|
b85b9d5421 | ||
|
|
42461a2b74 | ||
|
|
0343638c61 | ||
|
|
f26710bb38 | ||
|
|
c2d5110c75 | ||
|
|
5935302ae7 | ||
|
|
b3ad5cc8e3 | ||
|
|
8807595f20 | ||
|
|
762eed1d18 | ||
|
|
64ef171b7d | ||
|
|
57219547f1 | ||
|
|
84d51e1994 | ||
|
|
4d6eaf7f1d | ||
|
|
431ffd6066 | ||
|
|
73ba70856c | ||
|
|
49d8e8b65f | ||
|
|
a4fa1ef776 | ||
|
|
4fd71874a9 | ||
|
|
7da58ba1ea | ||
|
|
afd66bdeca | ||
|
|
da4a208cd6 | ||
|
|
85182bd1e0 | ||
|
|
b474c28911 | ||
|
|
51e1e2e22e | ||
|
|
238db28b3f | ||
|
|
313535a88a | ||
|
|
ae0e1a513e | ||
|
|
bb1af42d54 | ||
|
|
4c7fa938d0 | ||
|
|
0b7b4a6696 | ||
|
|
deaa8b3ec4 | ||
|
|
6b5da6e016 | ||
|
|
4ea3b4dd93 | ||
|
|
d29e8e9528 | ||
|
|
cf80b02157 | ||
|
|
7284a1d769 | ||
|
|
6086460c84 | ||
|
|
28ae35aee7 | ||
|
|
cff35013b2 | ||
|
|
48865b04c0 | ||
|
|
559629ac76 | ||
|
|
93b2001b76 | ||
|
|
1f33f68959 | ||
|
|
ca3534ec58 | ||
|
|
0530aad684 | ||
|
|
6dfd311157 | ||
|
|
fd23a54520 | ||
|
|
75df7c70d1 | ||
|
|
0cfa1a9425 | ||
|
|
14c0c4bf65 | ||
|
|
59be41125c | ||
|
|
66db1ee8e0 | ||
|
|
c28373cda2 | ||
|
|
7260a0f3c7 | ||
|
|
3b10a48e86 | ||
|
|
3ced8ad563 | ||
|
|
1f2ce52479 | ||
|
|
0c7c2b8006 | ||
|
|
3002807ab5 | ||
|
|
a7011eceed | ||
|
|
bb547f147f | ||
|
|
967b8d84fa | ||
|
|
b6715f833a | ||
|
|
3edbf4fda1 | ||
|
|
112697d753 | ||
|
|
727dee5c1c | ||
|
|
df542e0077 | ||
|
|
36dc01d2aa | ||
|
|
237d26ffa7 | ||
|
|
7a1ed7aa52 | ||
|
|
5e10246876 | ||
|
|
76172e1a9e | ||
|
|
2b3747272a | ||
|
|
eec9335a90 | ||
|
|
de56704363 | ||
|
|
dd46a44c89 | ||
|
|
f69b98aae9 | ||
|
|
5d37db2b9a | ||
|
|
60977667f9 | ||
|
|
0bd136de59 | ||
|
|
344004d773 | ||
|
|
7193713c75 | ||
|
|
b63f4b4868 | ||
|
|
5271989382 | ||
|
|
26f9313d4c | ||
|
|
0b3cd922b4 | ||
|
|
e302e38092 | ||
|
|
ac3a5ecd58 | ||
|
|
2db8d0cb0a | ||
|
|
4f40c81f3a | ||
|
|
a2e4c25614 | ||
|
|
bb72921ee9 | ||
|
|
c50602a9e9 | ||
|
|
5b06e5fd52 | ||
|
|
396dd976c5 | ||
|
|
91c384d3b9 | ||
|
|
eb7b4bbaf5 | ||
|
|
bbd784cfb8 | ||
|
|
136999e3b1 | ||
|
|
6e34681227 | ||
|
|
677d1ce4d0 | ||
|
|
c3d608131c | ||
|
|
d2a99e9fd1 | ||
|
|
ea20108c87 | ||
|
|
4ef71b76dd | ||
|
|
bdc233c47c | ||
|
|
cf3f1bebfb | ||
|
|
89bfa33fbf | ||
|
|
67e90ac89b | ||
|
|
e13f45c831 | ||
|
|
a66b625459 | ||
|
|
22e5d9d255 | ||
|
|
100be4e00b | ||
|
|
0a30937f9a | ||
|
|
118d6c7cad | ||
|
|
28beac2c8c | ||
|
|
7056077cd5 | ||
|
|
b6ad1a0ab7 | ||
|
|
64cb6b3e81 | ||
|
|
3746205277 | ||
|
|
118e28f9ae | ||
|
|
9cb7b0d344 | ||
|
|
a2a8f51509 | ||
|
|
4d52acf0be | ||
|
|
ab1e6adf85 | ||
|
|
5f0d04df2c | ||
|
|
067aadc8ea | ||
|
|
7977358ae1 | ||
|
|
1ae55c56f1 | ||
|
|
8dccbcb637 | ||
|
|
47135983f3 | ||
|
|
6d4d5162fe | ||
|
|
a30f0ceea4 | ||
|
|
161de50759 | ||
|
|
012fa0d838 | ||
|
|
057f38dbf6 | ||
|
|
04de0fcfb4 | ||
|
|
cfb7d00c63 | ||
|
|
dd218b36bc | ||
|
|
2cabf45a03 | ||
|
|
c26351cb64 | ||
|
|
a37714cf2d | ||
|
|
587ce331f5 | ||
|
|
7335ebf130 | ||
|
|
0db079b57c | ||
|
|
135b783b2b | ||
|
|
3264717e54 | ||
|
|
94e43c1e78 | ||
|
|
e03052c0a7 | ||
|
|
ef6c2ad5ff | ||
|
|
b3e7b3b3b2 | ||
|
|
ed31471e4f | ||
|
|
20db0ac775 | ||
|
|
e4c1164b7a | ||
|
|
2ec3b0e232 | ||
|
|
c7f310da18 | ||
|
|
5d11841e4a | ||
|
|
804a60f169 | ||
|
|
d9176f84b5 | ||
|
|
27d37b5519 | ||
|
|
9861b67ab1 | ||
|
|
40f1810322 | ||
|
|
abcc4f318f | ||
|
|
34602a43da | ||
|
|
3f57b8cac3 | ||
|
|
51994670f9 | ||
|
|
0ce0b16a33 | ||
|
|
947225a8ce | ||
|
|
173c29d76f | ||
|
|
a77a433303 | ||
|
|
c3ee1b3975 | ||
|
|
a41089d8f2 | ||
|
|
5c26b304da | ||
|
|
20020bc97f | ||
|
|
c2fcca0ed5 | ||
|
|
3624823d71 | ||
|
|
e0bfcf7d5a | ||
|
|
a0df064a76 | ||
|
|
fb710722b5 | ||
|
|
8f21a6a6d8 | ||
|
|
9045f1c2a3 | ||
|
|
fd23d6ec55 | ||
|
|
fdaa22e435 | ||
|
|
a8671c27f6 | ||
|
|
540e091661 | ||
|
|
064ff5d338 | ||
|
|
3b22331bb1 | ||
|
|
c9d882bf71 | ||
|
|
2c76209b08 | ||
|
|
0299987a17 | ||
|
|
5a17d84a86 | ||
|
|
b637d83a93 | ||
|
|
811ce25a7f | ||
|
|
7e822d0bb3 | ||
|
|
d6f69499bc | ||
|
|
1214e3a885 | ||
|
|
0363713fb6 | ||
|
|
ba2507cdab | ||
|
|
60ccc22e20 | ||
|
|
34410393f1 | ||
|
|
88cdcc6ebb | ||
|
|
306b4a9087 | ||
|
|
4e09b5bc2c | ||
|
|
755be49173 | ||
|
|
ab83ed2500 | ||
|
|
71c7ef1ae2 | ||
|
|
99fd783aa6 | ||
|
|
6d9b21dcad | ||
|
|
e08078b050 | ||
|
|
a5630d47ba | ||
|
|
8449e3e261 | ||
|
|
ae41533e60 | ||
|
|
0d13425ae2 | ||
|
|
0a613a7f14 | ||
|
|
601294ae91 | ||
|
|
58dc0576c3 | ||
|
|
25dcf204f6 | ||
|
|
6ca76cce58 | ||
|
|
45e8fd8414 | ||
|
|
b838f148a8 | ||
|
|
605309ef33 | ||
|
|
f19fcd5abb | ||
|
|
6f6d97af07 | ||
|
|
73b26beb86 | ||
|
|
8a0e6f6b29 | ||
|
|
50c9be6bcf | ||
|
|
a6832c864d | ||
|
|
f2b0adf9d4 | ||
|
|
da1541c6fb | ||
|
|
2bf277a627 | ||
|
|
a04e60eec8 | ||
|
|
16c5cb96b5 | ||
|
|
7ff18f2808 | ||
|
|
b1c712bd79 | ||
|
|
6266a6e9da | ||
|
|
e61bb5159d | ||
|
|
052b8b0834 | ||
|
|
56566ef997 | ||
|
|
5bd0b64e4c | ||
|
|
07fb6624eb | ||
|
|
824d3a876f | ||
|
|
f6c457759e | ||
|
|
d8d65b19f4 | ||
|
|
2c15a6fd99 |
No files matched your search
@@ -0,0 +1,25 @@
|
||||
# Editorconfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
continuation_indent_size = 8
|
||||
|
||||
[*.java]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.xml]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
@@ -0,0 +1,7 @@
|
||||
name: Build
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
call_build:
|
||||
uses: CivMC/.github/.github/workflows/gradle_build.yml@master
|
||||
@@ -0,0 +1,8 @@
|
||||
name: Publish
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
call_publish:
|
||||
uses: CivMC/.github/.github/workflows/gradle_publish.yml@master
|
||||
+6
-1
@@ -3,4 +3,9 @@
|
||||
/bin/
|
||||
.project
|
||||
.classpath
|
||||
.metadata
|
||||
.metadata
|
||||
.idea/
|
||||
*.iml
|
||||
logs
|
||||
build
|
||||
.gradle
|
||||
File renamed without changes.
@@ -0,0 +1,229 @@
|
||||
Simple Admin Hacks
|
||||
==================
|
||||
|
||||
Landing spot for fixes, tuning, micro game modifications that have no other home.
|
||||
|
||||
This is tweak central.
|
||||
|
||||
Brought to you by DevotedMC, we're taking a pretty inclusive and permissive view for this plugin; if you need a
|
||||
particular "hack" to get things working in your use case, send us a PR for inclusion, we'd love to host it.
|
||||
|
||||
This plugin is designed from the ground up to support easy creation of "microplugins" -- things with featuresets too
|
||||
small to make sense for a full sized plugin, or fixes for game problems or simple heuristic loggers.
|
||||
|
||||
Making a new "Hack" is always an option, but take a look at this list of active Hacks and see if your contribution
|
||||
might fit with an existing module.
|
||||
|
||||
## Active Hacks
|
||||
|
||||
Any hack can be theoretically live-disabled and enabled using:
|
||||
`hacks <hackname> enable` or `hacks <hackname> disable` where the hackname is
|
||||
as listed.
|
||||
|
||||
Type `hacks` to see what the current enable/disable status of all loaded hacks is.
|
||||
|
||||
Type `hacks <hackname>` to see a readout of that particular hack's status or config.
|
||||
|
||||
Type `hacks <hackname> get <configitem>` to see the current configuration setting for that config element in that hack.
|
||||
|
||||
Type `hacks <hackname> set <configitem> <new value>` to set a new configuratoin value for that config element in that
|
||||
hack. Not all hacks support this.
|
||||
|
||||
### AntiFastBreak
|
||||
|
||||
This hack offers some defence against insta-break / fast-break client hacks by denying continuous breaks.
|
||||
|
||||
### ArthropodEggHack
|
||||
|
||||
Allows players to occasionally pick up spawn eggs of mobs they kill with Bane of Arthropods.
|
||||
|
||||
### AttrHider
|
||||
|
||||
Stops clients from receiving extraneous entity and item data that could be exploited custom clients.
|
||||
|
||||
### AutoRespawn
|
||||
|
||||
This hack allows administrators to enforce a limit on how long players can stay dead, preventing zombie scouting and
|
||||
safe bots.
|
||||
|
||||
### BuffSpanker
|
||||
|
||||
Disables particular \[potion\] effects from being applied to players through standard means.
|
||||
|
||||
### DebugWand
|
||||
|
||||
Gives administrators the ability to spawn in a wand that when right clicked on blocks and entities will display useful
|
||||
debug information.
|
||||
|
||||
### EventDebugHack
|
||||
|
||||
This hack allows administrators to inspect an event as it passes through the stages of priority, what listeners are
|
||||
handling the event at what stage, and if applicable when exactly the even is cancelled.
|
||||
|
||||
### EventHandlerList
|
||||
|
||||
This hack lets you search for all the events *currently* being listened for with your current plugin setup and those
|
||||
listeners' class names.
|
||||
|
||||
### HumbugBatchOne
|
||||
|
||||
A new BasicHack (thanks Maxopoly) which encompasses a number of previously unincluded Humbug gameplay modifications.
|
||||
Specifically, sheep wool dying, anvil use, enchanting table use, cauldrons sourcing infinite water, disabling Ender
|
||||
Dragon, disabling iron farms, disabling Ender Crystal damage, disable mining fatigue, and equipping banners as hats.
|
||||
|
||||
### ItemMetaConverterHack
|
||||
|
||||
Passively upgrades the lore and display name text under the hood from legacy strings to components.
|
||||
|
||||
### OldEnchanting
|
||||
|
||||
This hack allows admins to regulate XP and enchantments in particular ways.
|
||||
|
||||
### PhantomMenace
|
||||
|
||||
Allows administrators to regulate the behaviour of phantoms and their spawning.
|
||||
|
||||
### PlayerRevive
|
||||
|
||||
Administrators can force revive a player where they died.
|
||||
|
||||
### PlayerStatistics
|
||||
|
||||
Allows administrators to view and set a player's [statistics](https://minecraft.gamepedia.com/Statistics).
|
||||
|
||||
### PortalSpawnModifier
|
||||
|
||||
Another new BasicHack which allows control of the spawn of creatures rate from nether portals
|
||||
|
||||
### ShipOutOfLuck
|
||||
|
||||
Allows administrators to disallow boating on particular blocks.
|
||||
|
||||
### TestConfigHack
|
||||
|
||||
Test hack for SimpleAdminHacks itself. Please [make a fuss](https://github.com/CivClassic/SimpleAdminHacks/issues/new)
|
||||
if you see any red.
|
||||
|
||||
### BadBoyWatch
|
||||
|
||||
This hack keeps track of who breaks what, and what they broke to get there. I've got bigger plans for more heuristics
|
||||
but for now, that's it. Please, feel free to improve on this.
|
||||
|
||||
### CTAnnounce
|
||||
|
||||
An integration into CombatTagPlus, this announces to in-game operators when combat is under way. Invaluable when you
|
||||
like your admins to monitor in-game fights.
|
||||
|
||||
### Experimental
|
||||
|
||||
This is a catch-all for anything micro that has no other home. Useful features like `/serialize` command live here too,
|
||||
but mostly its logging trackers that are great for debugging edge cases and useless for normal runtime.
|
||||
|
||||
### GameFeatures
|
||||
|
||||
The principle focus here is on enabling and disabling game features, like elytra or skulker boxes or those sorts of
|
||||
things. Try to keep the focus on boolean or otherwise simple on / off or discrete state options that relate to existing
|
||||
Minecraft game mechanics.
|
||||
|
||||
### GameFixes
|
||||
|
||||
Sometimes things in Minecraft just... don't work. Or don't work the way you want them to. Put those fixes here.
|
||||
|
||||
### GameTuning
|
||||
|
||||
Similar to Game Fixes, but distinct in that the intent here is on hacks that *tune* or alter existing mechanics without
|
||||
fully disabling them or without fixing them. Things like altering armor damage reduction or tool impact would be good
|
||||
fits.
|
||||
|
||||
### ~~HackBot~~
|
||||
|
||||
(Removed in 1.2.4)
|
||||
~~An experimental module whose complexity is approaching divorce from SAH, this is a bit of mid-work code that allows
|
||||
operators to define static Bots that show up like "real" players but aren't.~~
|
||||
|
||||
### HorseStats
|
||||
|
||||
This hack allows player's to view a horse's stats.
|
||||
|
||||
### Introbook
|
||||
|
||||
Allows the creation of customizeable, helpful first join books that are distributed to players when they first join the
|
||||
server. Safe to turn off but super useful if you have a core set of additional "good to know" information or
|
||||
introductory material you'd like players to receive.
|
||||
|
||||
### InvControl
|
||||
|
||||
Host of the `/invsee` command, gives insight into active player inventory, armor, health and more. I hope / intend to
|
||||
add another portion to this that allows online and offline inventory management via `/invmod` but this is as of now not
|
||||
started.
|
||||
|
||||
### ~~InvisibleFix and InvisibleFixTwo~~
|
||||
|
||||
(Removed in 1.3.0)
|
||||
~~My hope is to remove these in time, but for 1.9 and 1.10 minecraft players go invisible all the time. Both of these
|
||||
hacks use different approaches to help preserve the visiblity of players. The second hack is the more invasive, sending
|
||||
explicit location packets when the situation indicates its usefulness.~~
|
||||
|
||||
### NewfriendAssist
|
||||
|
||||
A new join tracker, that also doubles as an introkit delivery mechanism. It also exposes the `introkit` command you can
|
||||
use to send specific people a new introkit if they lost theirs.
|
||||
|
||||
### ReinforcedChestBreak
|
||||
|
||||
Another useful alerting hack, sends a message to online operators when players are actively breaking reinforced
|
||||
containers.
|
||||
|
||||
### SanityHack
|
||||
|
||||
This one is pretty Devoted iteration 3 specific. Allows tracking server wide of all breaks or builds under a specific
|
||||
Y level.
|
||||
|
||||
### TimingsHack
|
||||
|
||||
This is mature enough to be its own plugin now, but for the moment I'm leaving it in because IMHO it is an essential
|
||||
component for debugging and maintaining your server.
|
||||
|
||||
This hack begins where /timings and warmroast end. It generates in-game visualizations of per-tick time utilization,
|
||||
and allows you to investigate with extreme effectiveness exactly what is causing instantaneous or irregular lag. Things
|
||||
that average out, but lead to bad experiences for players.
|
||||
|
||||
To use it, there are a number of important commands.
|
||||
|
||||
First:
|
||||
|
||||
* `/showtimings` This gives the requester a "map" object that paints a heatmap, heightmap, and linegraph of TPS. Each
|
||||
vertical pixel is a full 20 ticks; each dot in the heatmap is a single tick. The heightmap above the heatmap
|
||||
(heatmap is on the bottom) is both colored and sized based on time-in-tick. At the very top is line graph of
|
||||
relative "health" of the tick. The closer to the grey line the better; the closer to the top, the worse.
|
||||
* `/thresholdtimings` This starts a very high resolution (1ms) stack inspection tracker. It keeps track *per tick*
|
||||
with usually 50 samples per tick of which methods and classes are being taking up time within the tick. Give it a
|
||||
threshold factor -- please, something more then 1, 5 to 10 works well -- where any tick that takes longer then
|
||||
threshold factor * average tick length, dumps the class/method list to requestor (either console or in-game
|
||||
character). The list is in sorted order of class where most time is spent down to class where least time is spent.
|
||||
* `/listtimings` In you already suspect something, you can use this command to begin a spammy dump of all classes
|
||||
encountered during high-resolution tracking. Only new classes are printed, and it shuts itself off if nothing new
|
||||
has been printed for a full second.
|
||||
* `/bindtimings` This generates an in-game map displaying (like `/showtimings`) a heatmap, heightmap, and line graph
|
||||
of per-tick utilization of any Classes that _contain_ whatever is passed in after bindtimings. Note this is saved,
|
||||
and on reload of the server if HQ timings are restarted those maps will re-bind to the saved bindings. This is a
|
||||
massively useful deep inspection tool; you can put the "based" class of a suspect plugin as the parameter, and
|
||||
watch its actual per-tick time utilization in real-time. Destroy the map object to release the drain on overall TPS
|
||||
that results from the comparison functions used to update the map.
|
||||
* `/stoptimings` This turns off any HQ functions. Has the impact of _pausing_ any bindtimings maps, and releasing all
|
||||
HQ functions from impacting Tick (also stops tracking data, so data tracking will reset if HQ restarted by calling
|
||||
any other HQ-tagged command).
|
||||
|
||||
In game example with some descriptions:
|
||||
|
||||
* From live server: http://imgur.com/a/zWNWo
|
||||
|
||||
### ToggleLamp
|
||||
|
||||
A solid piece of contributed code, this hack lets player's turn on and off redstone lamps without requiring any
|
||||
additional redstone infrastructure.
|
||||
|
||||
## Conclusion
|
||||
|
||||
There is room for many more hacks and the list grows regularly. The pattern is simple; check any of the existing hacks
|
||||
for details by example.
|
||||
@@ -0,0 +1,61 @@
|
||||
import net.civmc.civgradle.common.util.civRepo
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
id("net.civmc.civgradle.plugin") version "1.0.0-SNAPSHOT"
|
||||
}
|
||||
|
||||
// Temporary hack:
|
||||
// Remove the root build directory
|
||||
gradle.buildFinished {
|
||||
project.buildDir.deleteRecursively()
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = "net.civmc.simpleadminhacks"
|
||||
version = "2.0.0-SNAPSHOT"
|
||||
description = "SimpleAdminHacks"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply(plugin = "net.civmc.civgradle.plugin")
|
||||
apply(plugin = "java-library")
|
||||
apply(plugin = "maven-publish")
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
civRepo("CivMC/CivModCore")
|
||||
civRepo("CivMC/NameLayer")
|
||||
civRepo("CivMC/Citadel")
|
||||
civRepo("CivMC/CombatTagPlus")
|
||||
civRepo("CivMC/BanStick")
|
||||
maven("https://repo.dmulloy2.net/repository/public/")
|
||||
maven("https://ci.frostcast.net/plugin/repository/everything")
|
||||
maven("https://jitpack.io")
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/CivMC/SimpleAdminHacks")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
publications {
|
||||
register<MavenPublication>("gpr") {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
+5
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,24 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
id("net.civmc.civgradle.plugin")
|
||||
id("io.papermc.paperweight.userdev") version "1.3.1"
|
||||
}
|
||||
|
||||
civGradle {
|
||||
paper {
|
||||
pluginName = "SimpleAdminHacks"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
paperDevBundle("1.18.1-R0.1-SNAPSHOT")
|
||||
|
||||
compileOnly("net.civmc.civmodcore:paper:2.0.0-SNAPSHOT:dev-all")
|
||||
compileOnly("net.civmc.namelayer:paper:3.0.0-SNAPSHOT:dev")
|
||||
compileOnly("net.civmc.citadel:paper:5.0.0-SNAPSHOT:dev")
|
||||
compileOnly("net.civmc.combattagplus:paper:2.0.0-SNAPSHOT:dev")
|
||||
compileOnly("net.civmc.banstick:paper:2.0.0-SNAPSHOT:dev")
|
||||
|
||||
compileOnly("com.comphenix.protocol:ProtocolLib:4.8.0")
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.HackManager;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.commands.CommandRegistrar;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.entity.Player;
|
||||
import vg.civcraft.mc.civmodcore.ACivMod;
|
||||
|
||||
/**
|
||||
* Wrapper for simple admin hacks, each doing a thing and each configurable.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class SimpleAdminHacks extends ACivMod {
|
||||
|
||||
private static SimpleAdminHacks plugin;
|
||||
|
||||
private final SimpleAdminHacksConfig config;
|
||||
private final HackManager manager;
|
||||
private CommandRegistrar commands;
|
||||
private final SimpleAdminHacksSettingManager settingManager;
|
||||
|
||||
public SimpleAdminHacks() {
|
||||
plugin = this;
|
||||
this.config = new SimpleAdminHacksConfig(this);
|
||||
this.manager = new HackManager(this);
|
||||
this.settingManager = new SimpleAdminHacksSettingManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
if (!this.config.parse()) {
|
||||
setEnabled(false);
|
||||
return;
|
||||
}
|
||||
this.manager.loadAllHacks();
|
||||
this.commands = new CommandRegistrar(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.manager.disableAllHacks();
|
||||
this.commands.reset();
|
||||
this.config.reset();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
public void registerCommand(final String identifier, final CommandExecutor executor) {
|
||||
final PluginCommand command = getCommand(identifier);
|
||||
if (command != null) {
|
||||
command.setExecutor(executor);
|
||||
}
|
||||
else {
|
||||
warning("Failed to register Executor for " + identifier + ", " +
|
||||
"please define that command in the plugin.yml first.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Definitely not safe. Used for Insight hack.
|
||||
* @return the ClassLoader for this plugin.
|
||||
*/
|
||||
public ClassLoader exposeClassLoader() {
|
||||
return getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the overall config management for this plugin.
|
||||
*/
|
||||
public SimpleAdminHacksConfig config() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the hack manager
|
||||
*/
|
||||
public HackManager getHackManager() {
|
||||
return this.manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the command registrar
|
||||
*/
|
||||
public CommandRegistrar getCommands() {
|
||||
return this.commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the pseudo-singleton instance of this plugin.
|
||||
*/
|
||||
public static SimpleAdminHacks instance() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CivModCore PlayerSetting Manager
|
||||
* @return
|
||||
*/
|
||||
|
||||
public SimpleAdminHacksSettingManager getSettingManager() {
|
||||
return settingManager;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Deprecated
|
||||
// ------------------------------------------------------------
|
||||
|
||||
@Deprecated
|
||||
public void log(String message) {
|
||||
info(message);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void log(Level level, String message) {
|
||||
getLogger().log(level, message);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void log(Level level, String message, Throwable thrown) {
|
||||
getLogger().log(level, message, thrown);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void log(Level level, String message, Object object) {
|
||||
getLogger().log(level, message, object);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void log(Level level, String message, Object...objects) {
|
||||
getLogger().log(level, message, objects);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean serverHasPlugin(String pluginName) {
|
||||
return this.getServer().getPluginManager().isPluginEnabled(pluginName);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int serverBroadcast(String message) {
|
||||
return this.getServer().broadcast(message, config().getBroadcastPermission());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int serverOperatorBroadcast(String message) {
|
||||
int cnt = 0;
|
||||
for(OfflinePlayer op : Bukkit.getOperators()) {
|
||||
if (op.isOnline() && op.getPlayer() != null) {
|
||||
op.getPlayer().sendMessage(message);
|
||||
cnt ++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int serverOnlineBroadcast(String message) {
|
||||
int cnt = 0;
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
if (p != null && p.isOnline()) {
|
||||
p.sendMessage(message);
|
||||
cnt ++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void serverSendConsoleMessage(String message) {
|
||||
Bukkit.getConsoleSender().sendMessage(message);
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import vg.civcraft.mc.civmodcore.config.ConfigParser;
|
||||
|
||||
/**
|
||||
* Baseline configuration for SimpleAdminHacks and parser for all actual Hacks.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class SimpleAdminHacksConfig extends ConfigParser {
|
||||
|
||||
private static final int EXPECTED_CONFIG_LEVEL = 1;
|
||||
|
||||
private static final String DEFAULT_BROADCAST_PERM = "simpleadmin.broadcast";
|
||||
|
||||
private String broadcastPermission;
|
||||
|
||||
public SimpleAdminHacksConfig(final SimpleAdminHacks plugin) {
|
||||
super(plugin);
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean parseInternal(final ConfigurationSection config) {
|
||||
final int actual_config_level = config.getInt("configuration_file_version", -1);
|
||||
if (actual_config_level < 0 || actual_config_level > SimpleAdminHacksConfig.EXPECTED_CONFIG_LEVEL) {
|
||||
this.plugin.getLogger().severe("Invalid configuration version!");
|
||||
return false;
|
||||
}
|
||||
this.broadcastPermission = config.getString("broadcast_permission", DEFAULT_BROADCAST_PERM);
|
||||
this.plugin.getLogger().info("Broadcast permission: " + this.broadcastPermission);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
super.reset();
|
||||
this.broadcastPermission = DEFAULT_BROADCAST_PERM;
|
||||
}
|
||||
|
||||
public String getBroadcastPermission() {
|
||||
return this.broadcastPermission;
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import vg.civcraft.mc.civmodcore.players.settings.PlayerSettingAPI;
|
||||
import vg.civcraft.mc.civmodcore.players.settings.gui.MenuSection;
|
||||
|
||||
public class SimpleAdminHacksSettingManager {
|
||||
|
||||
private MenuSection mainMenu;
|
||||
|
||||
public SimpleAdminHacksSettingManager() {
|
||||
this.mainMenu = PlayerSettingAPI.getMainMenu().createMenuSection("SimpleAdminHacks", "Config values for all small tweaks from SAH", new ItemStack(
|
||||
Material.CAULDRON));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Menu Section used to bundle together all SAH /config tweaks
|
||||
* @return SAH /config Menu
|
||||
*/
|
||||
public MenuSection getMainMenu() {
|
||||
return mainMenu;
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Configures this hack, determines which blocks to watch and the like.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class BadBoyWatchConfig extends SimpleHackConfig {
|
||||
|
||||
private int trackingDepth;
|
||||
private boolean clearOnMatch;
|
||||
private int minDepthToMatch;
|
||||
private Set<Material> watchedMaterials;
|
||||
|
||||
private static final List<Material> defaultWatched = Arrays.asList(
|
||||
Material.CHEST,
|
||||
Material.JUKEBOX,
|
||||
Material.NOTE_BLOCK,
|
||||
Material.BEACON,
|
||||
Material.ENCHANTING_TABLE,
|
||||
Material.ENDER_CHEST,
|
||||
Material.FURNACE,
|
||||
Material.SPONGE);
|
||||
|
||||
public BadBoyWatchConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.trackingDepth = config.getInt("trackingDepth", 8); // keep up to 8 breaks
|
||||
plugin().log(Level.INFO, " Tracking Depth: {0}", this.trackingDepth);
|
||||
this.clearOnMatch = config.getBoolean("clearOnMatch", true); // once you print out don't keep old records
|
||||
plugin().log(Level.INFO, " Clear On Match: {0}", this.clearOnMatch);
|
||||
this.minDepthToMatch = config.getInt("minDepthToMatch", 2); // this block + 1
|
||||
plugin().log(Level.INFO, " Minimum Breakpath Depth To Match: {0}", this.minDepthToMatch);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> watch = (List<String>) config.getList("watchedMaterials");
|
||||
this.watchedMaterials = new HashSet<>();
|
||||
if (watch == null || watch.isEmpty()) {
|
||||
this.watchedMaterials.addAll(defaultWatched);
|
||||
plugin().log(Level.INFO, " Adding default watch set");
|
||||
} else {
|
||||
for (String mat : watch) {
|
||||
try {
|
||||
Material nmat = Material.matchMaterial(mat);
|
||||
this.watchedMaterials.add(nmat);
|
||||
plugin().log(Level.INFO, " Watching material {0}", nmat);
|
||||
} catch (Exception e) {
|
||||
plugin().log(Level.WARNING, " Invalid material {0} listed", mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getTrackingDepth() {
|
||||
return trackingDepth;
|
||||
}
|
||||
|
||||
public boolean isClearOnMatch() {
|
||||
return clearOnMatch;
|
||||
}
|
||||
|
||||
public int getMinDepthToMatch() {
|
||||
return minDepthToMatch;
|
||||
}
|
||||
|
||||
public Set<Material> getWatchedMaterials() {
|
||||
return watchedMaterials;
|
||||
}
|
||||
|
||||
}
|
||||
+12
-14
@@ -1,15 +1,13 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.BroadcastLevel;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.BroadcastLevel;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
|
||||
|
||||
/**
|
||||
* CombatTag event hook hack
|
||||
*
|
||||
@@ -17,7 +15,7 @@ import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
|
||||
*
|
||||
*/
|
||||
public class CTAnnounceConfig extends SimpleHackConfig {
|
||||
|
||||
|
||||
/**
|
||||
* Who should I broadcast to?
|
||||
*/
|
||||
@@ -39,40 +37,40 @@ public class CTAnnounceConfig extends SimpleHackConfig {
|
||||
public CTAnnounceConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
|
||||
public CTAnnounceConfig(ConfigurationSection base) {
|
||||
super(SimpleAdminHacks.instance(), base);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.broadcastDelay = config.getLong("delay", 5000l);
|
||||
this.broadcastMessage = config.getString("message", "%Victim% was combat tagged by %Attacker%");
|
||||
|
||||
|
||||
plugin().log(Level.INFO, " delay: {0}, message: {1}", this.broadcastDelay, this.broadcastMessage);
|
||||
|
||||
|
||||
List<String> broadcastTo = config.getStringList("broadcast");
|
||||
if (this.broadcast == null) {
|
||||
this.broadcast = new LinkedList<BroadcastLevel>();
|
||||
}
|
||||
|
||||
|
||||
this.broadcast.clear();
|
||||
|
||||
if (broadcastTo == null) {
|
||||
this.setEnabled(false); // disable if no broadcasters.
|
||||
setShouldEnable(false); // disable if no broadcasters.
|
||||
}
|
||||
|
||||
for (String type : broadcastTo) {
|
||||
try {
|
||||
broadcast.add(BroadcastLevel.valueOf(type));
|
||||
|
||||
|
||||
plugin().log(Level.INFO, " broadcast: {0}", type);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<BroadcastLevel> getBroadcast() {
|
||||
return broadcast;
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import vg.civcraft.mc.civmodcore.config.ConfigHelper;
|
||||
import vg.civcraft.mc.civmodcore.utilities.CivLogger;
|
||||
|
||||
public final class DisableAIConfig extends SimpleHackConfig {
|
||||
|
||||
private final CivLogger logger;
|
||||
private final EnumMap<EntityType, List<CreatureSpawnEvent.SpawnReason>> mobAiLimitations;
|
||||
|
||||
public DisableAIConfig(final SimpleAdminHacks plugin, final ConfigurationSection base) {
|
||||
super(plugin, base, false);
|
||||
this.logger = CivLogger.getLogger(getClass());
|
||||
this.mobAiLimitations = new EnumMap<>(EntityType.class);
|
||||
wireup(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(final ConfigurationSection config) {
|
||||
for (final EntityType entityType : EntityType.values()) {
|
||||
if (!config.contains(entityType.name())) {
|
||||
continue;
|
||||
}
|
||||
if (!entityType.isAlive()) {
|
||||
this.logger.warning("EntityType [" + entityType.name() + "] is not alive.");
|
||||
continue;
|
||||
}
|
||||
final List<String> rawSpecifiedReasons = ConfigHelper.getStringList(config, entityType.name());
|
||||
rawSpecifiedReasons.removeIf(StringUtils::isBlank);
|
||||
if (CollectionUtils.isEmpty(rawSpecifiedReasons)) {
|
||||
this.logger.warning("EntityType [" + entityType.name() + "] did not specify any spawn reasons; " +
|
||||
"skipping. You should fix your config.");
|
||||
continue;
|
||||
}
|
||||
final var allSpawnReasons = CreatureSpawnEvent.SpawnReason.values();
|
||||
final var limitationReasons = this.mobAiLimitations.computeIfAbsent(entityType,
|
||||
(ignored) -> new ArrayList<>(allSpawnReasons.length));
|
||||
if (rawSpecifiedReasons.size() == 1 && "ALL".equalsIgnoreCase(rawSpecifiedReasons.get(0))) {
|
||||
limitationReasons.addAll(List.of(allSpawnReasons));
|
||||
continue;
|
||||
}
|
||||
for (final String rawSpecifiedReason : rawSpecifiedReasons) {
|
||||
final var matchedSpawnReason = EnumUtils.getEnumIgnoreCase(
|
||||
CreatureSpawnEvent.SpawnReason.class, rawSpecifiedReason);
|
||||
if (matchedSpawnReason == null) {
|
||||
this.logger.warning("EntityType [" + entityType.name() + "] specified an " +
|
||||
"invalid spawn reason: " + rawSpecifiedReason);
|
||||
continue;
|
||||
}
|
||||
if (limitationReasons.contains(matchedSpawnReason)) {
|
||||
this.logger.warning("EntityType [" + entityType.name() + "] already specifies " +
|
||||
"reason: " + rawSpecifiedReason);
|
||||
continue;
|
||||
}
|
||||
limitationReasons.add(matchedSpawnReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.mobAiLimitations.forEach((type, reasons) -> reasons.clear());
|
||||
this.mobAiLimitations.clear();
|
||||
}
|
||||
|
||||
public boolean isLimitingEntityAI(final EntityType entityType, final CreatureSpawnEvent.SpawnReason spawnReason) {
|
||||
if (entityType == null || spawnReason == null) {
|
||||
return false;
|
||||
}
|
||||
final var limitationReasons = this.mobAiLimitations.get(entityType);
|
||||
if (CollectionUtils.isEmpty(limitationReasons)) {
|
||||
return false;
|
||||
}
|
||||
return limitationReasons.contains(spawnReason);
|
||||
}
|
||||
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import javax.annotation.Nonnull;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import vg.civcraft.mc.civmodcore.utilities.CivLogger;
|
||||
|
||||
public final class ElytraFeaturesConfig extends SimpleHackConfig {
|
||||
private final CivLogger logger;
|
||||
|
||||
private boolean disableFlight;
|
||||
private boolean disableFlightInCombat;
|
||||
|
||||
private boolean disableFireworkBoosting;
|
||||
private boolean disableFireworkBoostingInCombat;
|
||||
private boolean disableSafeFireworkBoosting;
|
||||
|
||||
private int heightDamage;
|
||||
private double heightDamageScaling;
|
||||
private int heightBuffer;
|
||||
private long heightDamageInterval;
|
||||
|
||||
public ElytraFeaturesConfig(@Nonnull final SimpleAdminHacks plugin,
|
||||
@Nonnull final ConfigurationSection base) {
|
||||
super(plugin, base, false);
|
||||
this.logger = CivLogger.getLogger(getClass());
|
||||
wireup(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(@Nonnull final ConfigurationSection config) {
|
||||
this.disableFlight = config.getBoolean("disableFlight", false);
|
||||
|
||||
this.disableFlightInCombat = config.getBoolean("disableFlightInCombat", false);
|
||||
|
||||
this.disableFireworkBoosting = config.getBoolean("disableFireworkBoosting", false);
|
||||
|
||||
this.disableFireworkBoostingInCombat = config.getBoolean("disableFireworkBoostingInCombat", false);
|
||||
|
||||
this.disableSafeFireworkBoosting = config.getBoolean("disableSafeFireworkBoosting", false);
|
||||
|
||||
this.heightDamage = config.getInt("heightDamage.damage", 1);
|
||||
if (this.heightDamage < 0) {
|
||||
this.logger.warning("[heightDamage.damage] was set to [" + this.heightDamage + "], " +
|
||||
"which is invalid, defaulting to: 1");
|
||||
this.heightDamage = 1;
|
||||
}
|
||||
|
||||
this.heightDamageScaling = config.getDouble("heightDamage.scales", 1d);
|
||||
if (this.heightDamageScaling <= 0d) {
|
||||
this.logger.warning("[heightDamage.scales] was set to [" + this.heightDamageScaling + "], " +
|
||||
"which is invalid, defaulting to: 1.0d");
|
||||
this.heightDamageScaling = 1d;
|
||||
}
|
||||
|
||||
this.heightBuffer = config.getInt("heightDamage.buffer", 5);
|
||||
|
||||
this.heightDamageInterval = config.getLong("heightDamage.interval", 1000L);
|
||||
if (this.heightDamageInterval < 1L) {
|
||||
this.logger.warning("[heightDamage.interval] was set to [" + this.heightDamageInterval + "], " +
|
||||
"which is invalid, defaulting to: 1000L");
|
||||
this.heightDamageInterval = 1000L;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFlightDisabled() {
|
||||
return this.disableFlight;
|
||||
}
|
||||
|
||||
public boolean isFlightDisabledInCombat() {
|
||||
return this.disableFlightInCombat;
|
||||
}
|
||||
|
||||
public boolean isBoostingDisabled() {
|
||||
return this.disableFireworkBoosting;
|
||||
}
|
||||
|
||||
public boolean isBoostingDisabledInCombat() {
|
||||
return this.disableFireworkBoostingInCombat;
|
||||
}
|
||||
|
||||
public boolean isSafeBoostingDisabled() {
|
||||
return this.disableSafeFireworkBoosting;
|
||||
}
|
||||
|
||||
public int getHeightDamage() {
|
||||
return this.heightDamage;
|
||||
}
|
||||
|
||||
public double isHeightDamageScaling() {
|
||||
return this.heightDamageScaling;
|
||||
}
|
||||
|
||||
public int getHeightBuffer() {
|
||||
return this.heightBuffer;
|
||||
}
|
||||
|
||||
public long getHeightDamageInterval() {
|
||||
return this.heightDamageInterval;
|
||||
}
|
||||
|
||||
}
|
||||
+44
-45
@@ -1,45 +1,44 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
|
||||
|
||||
/**
|
||||
* Dumping ground for experimental stuff. Highly volatile. May explode.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*
|
||||
*/
|
||||
public class ExperimentalConfig extends SimpleHackConfig {
|
||||
private boolean combatSpy;
|
||||
private boolean teleportSpy;
|
||||
private boolean postTeleportSpy;
|
||||
private int postTeleportSpyCount;
|
||||
public ExperimentalConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.combatSpy = config.getBoolean("combatspy", false);
|
||||
this.teleportSpy = config.getBoolean("teleportspy", false);
|
||||
this.postTeleportSpy = config.getBoolean("postteleport.spy", false);
|
||||
this.postTeleportSpyCount = config.getInt("postteleport.count", 10);
|
||||
}
|
||||
|
||||
public boolean isCombatSpy() {
|
||||
return this.combatSpy;
|
||||
}
|
||||
public boolean isTeleportSpy() {
|
||||
return this.teleportSpy;
|
||||
}
|
||||
public boolean isPostTeleportSpy() {
|
||||
return this.postTeleportSpy;
|
||||
}
|
||||
|
||||
public int getPostTeleportSpyCount() {
|
||||
return this.postTeleportSpyCount;
|
||||
}
|
||||
}
|
||||
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Dumping ground for experimental stuff. Highly volatile. May explode.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*
|
||||
*/
|
||||
public class ExperimentalConfig extends SimpleHackConfig {
|
||||
private boolean combatSpy;
|
||||
private boolean teleportSpy;
|
||||
private boolean postTeleportSpy;
|
||||
private int postTeleportSpyCount;
|
||||
public ExperimentalConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.combatSpy = config.getBoolean("combatspy", false);
|
||||
this.teleportSpy = config.getBoolean("teleportspy", false);
|
||||
this.postTeleportSpy = config.getBoolean("postteleport.spy", false);
|
||||
this.postTeleportSpyCount = config.getInt("postteleport.count", 10);
|
||||
}
|
||||
|
||||
public boolean isCombatSpy() {
|
||||
return this.combatSpy;
|
||||
}
|
||||
public boolean isTeleportSpy() {
|
||||
return this.teleportSpy;
|
||||
}
|
||||
public boolean isPostTeleportSpy() {
|
||||
return this.postTeleportSpy;
|
||||
}
|
||||
|
||||
public int getPostTeleportSpyCount() {
|
||||
return this.postTeleportSpyCount;
|
||||
}
|
||||
}
|
||||
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Holds configurations for the GameFeatures module.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class GameFeaturesConfig extends SimpleHackConfig {
|
||||
|
||||
private boolean potatoXPEnabled;
|
||||
private boolean villagerTrading;
|
||||
private boolean witherSpawning;
|
||||
private boolean patrolSpawning;
|
||||
private boolean isPhantomSpawning;
|
||||
private boolean enderChestPlacement;
|
||||
private boolean enderChestUse;
|
||||
private boolean shulkerBoxUse;
|
||||
private boolean totemPowers;
|
||||
private boolean chorusFruitUse;
|
||||
|
||||
private boolean weepingAngel;
|
||||
private int weepingAngelEnv;
|
||||
private int weepingAngelPlayer;
|
||||
|
||||
private boolean blockWaterInHell;
|
||||
|
||||
private boolean minecartTeleport;
|
||||
private boolean obsidianGenerators;
|
||||
private boolean personalDeathMessages;
|
||||
private boolean disableNetheriteCrafting;
|
||||
|
||||
private boolean goldBlockTeleport;
|
||||
|
||||
public GameFeaturesConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.potatoXPEnabled = !config.getBoolean("disablePotatoXP", false);
|
||||
if (!this.potatoXPEnabled) plugin().log(" Potato XP Disabled");
|
||||
|
||||
this.villagerTrading = config.getBoolean("villagerTrading", false);
|
||||
if (!villagerTrading) plugin().log(" VillagerTrading is disabled");
|
||||
|
||||
this.witherSpawning = config.getBoolean("witherSpawning", false);
|
||||
if (!this.witherSpawning) plugin().log(" Wither Spawning is disabled");
|
||||
|
||||
this.patrolSpawning = config.getBoolean("patrolSpawning", false);
|
||||
if (!this.patrolSpawning) plugin().log("Patrol Spawning is disabled");
|
||||
|
||||
this.isPhantomSpawning = config.getBoolean("phantomSpawning", false);
|
||||
if (!this.isPhantomSpawning) plugin().log("Phantom Spawning is disabled");
|
||||
|
||||
this.enderChestPlacement = config.getBoolean("enderChestPlacement", true);
|
||||
if (!this.enderChestPlacement) plugin().log(" Placing EnderChests is disabled");
|
||||
|
||||
this.enderChestUse = config.getBoolean("enderChestUse", false);
|
||||
if (!this.enderChestUse) plugin().log(" Using EnderChests is disabled");
|
||||
|
||||
this.shulkerBoxUse = config.getBoolean("shulkerBoxUse", false);
|
||||
if (!this.shulkerBoxUse) plugin().log(" Using Shulker Boxes is disabled");
|
||||
|
||||
this.totemPowers = config.getBoolean("totemPower", false);
|
||||
if (!this.totemPowers) plugin().log(" Undeath via totems is disabled");
|
||||
|
||||
this.chorusFruitUse = config.getBoolean("chorusFruitTeleportation", false);
|
||||
if (!this.chorusFruitUse) {
|
||||
plugin().log(" Chorus Fruit Teleportation is disabled");
|
||||
}
|
||||
|
||||
this.weepingAngel = config.getBoolean("weepingAngel.enabled", false);
|
||||
if (this.weepingAngel) {
|
||||
this.weepingAngelEnv = config.getInt("weepingAngel.environment", 1);
|
||||
this.weepingAngelPlayer = config.getInt("weepingAngel.playerKill", 5);
|
||||
|
||||
plugin().log(" Weeping Angel is enabled. Times | Env[" + weepingAngelEnv + "] PK[" + weepingAngelPlayer + "]");
|
||||
}
|
||||
|
||||
this.blockWaterInHell = config.getBoolean("blockWaterInHell", true);
|
||||
if (this.blockWaterInHell) plugin().log(" Blocking bucket use in hell biomes");
|
||||
|
||||
this.minecartTeleport = config.getBoolean("minecartTeleport", false);
|
||||
if (this.minecartTeleport) plugin().log(" Minecart teleporter enabled");
|
||||
|
||||
this.obsidianGenerators = config.getBoolean("obsidianGenerators", false);
|
||||
if (this.obsidianGenerators) plugin().log(" Obsidian generators enabled.");
|
||||
|
||||
this.personalDeathMessages = config.getBoolean("personalDeathMessages", false);
|
||||
if (this.personalDeathMessages) plugin().log(" Personal death messages enabled.");
|
||||
|
||||
this.disableNetheriteCrafting = config.getBoolean("disableNetheriteCrafting", true);
|
||||
if (this.disableNetheriteCrafting) plugin().log(" Disable Netherite Crafting enabled.");
|
||||
|
||||
this.goldBlockTeleport = config.getBoolean("goldBlockTeleport", false);
|
||||
if (this.personalDeathMessages) plugin().log(" Gold block teleporter enabled.");
|
||||
|
||||
/* Add additional feature config grabs here. */
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If getting XP from potatos is enabled.
|
||||
*/
|
||||
public boolean isPotatoXPEnabled() {
|
||||
return this.potatoXPEnabled;
|
||||
}
|
||||
|
||||
public boolean isVillagerTrading() {
|
||||
return this.villagerTrading;
|
||||
}
|
||||
|
||||
public boolean isWitherSpawning() {
|
||||
return this.witherSpawning;
|
||||
}
|
||||
|
||||
public boolean isPatrolSpawning() {
|
||||
return this.patrolSpawning;
|
||||
}
|
||||
|
||||
public boolean isPhantomSpawning() {
|
||||
return this.isPhantomSpawning;
|
||||
}
|
||||
|
||||
public boolean isEnderChestPlacement() {
|
||||
return this.enderChestPlacement;
|
||||
}
|
||||
|
||||
public boolean isEnderChestUse() {
|
||||
return this.enderChestUse;
|
||||
}
|
||||
|
||||
public boolean isShulkerBoxUse() {
|
||||
return this.shulkerBoxUse;
|
||||
}
|
||||
|
||||
public boolean isTotemPowers() {
|
||||
return this.totemPowers;
|
||||
}
|
||||
|
||||
public boolean isChorusFruitTeleportation() {
|
||||
return this.chorusFruitUse;
|
||||
}
|
||||
|
||||
public boolean isWeepingAngel() {
|
||||
return this.weepingAngel;
|
||||
}
|
||||
|
||||
public int getWeepingAngelEnv() {
|
||||
return this.weepingAngelEnv;
|
||||
}
|
||||
|
||||
public int getWeepingAngelPlayer() {
|
||||
return this.weepingAngelPlayer;
|
||||
}
|
||||
|
||||
public boolean isBlockWaterInHell() {
|
||||
return this.blockWaterInHell;
|
||||
}
|
||||
|
||||
public boolean isMinecartTeleport() {
|
||||
return this.minecartTeleport;
|
||||
}
|
||||
|
||||
public boolean isObsidianGenerators() {
|
||||
return this.obsidianGenerators;
|
||||
}
|
||||
|
||||
public boolean isPersonalDeathMessages() {
|
||||
return this.personalDeathMessages;
|
||||
}
|
||||
|
||||
public boolean isDisableNetheriteCrafting() {
|
||||
return this.disableNetheriteCrafting;
|
||||
}
|
||||
|
||||
public boolean isGoldblockTeleport() {
|
||||
return goldBlockTeleport;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public class GameFixesConfig extends SimpleHackConfig {
|
||||
|
||||
private boolean blockElytraBreakBug;
|
||||
private double damageOnElytraBreakBug;
|
||||
private boolean canStorageTeleport;
|
||||
private boolean stopHopperDupe;
|
||||
private boolean stopRailDupe;
|
||||
private boolean stopEndPortalDeletion;
|
||||
private boolean stopBedBombing;
|
||||
private boolean stopAnchorBombing;
|
||||
|
||||
private ArrayList<BlockFace> bfArray;
|
||||
private ArrayList<Material> railArray;
|
||||
private ArrayList<Material> pistonArray;
|
||||
|
||||
private boolean preventTreeWrap;
|
||||
private boolean maintainFlatBedrock;
|
||||
private boolean fixPearlGlitch;
|
||||
private boolean preventLongSigns;
|
||||
private int signLengthLimit;
|
||||
private boolean preventLongSignsAbsolute;
|
||||
private boolean cancelLongSignEvent;
|
||||
private boolean hardLimitBookPageSize;
|
||||
|
||||
public GameFixesConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
wireUpArrays();
|
||||
}
|
||||
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
blockElytraBreakBug = config.getBoolean("blockElytraBreakBug", true);
|
||||
damageOnElytraBreakBug = config.getDouble("damageOnElytraBreakBug", 0.0d);
|
||||
if (blockElytraBreakBug) plugin().log(Level.INFO, " Block Elytra 1height break bug is enabled, doing {} damage to violators", damageOnElytraBreakBug);
|
||||
|
||||
canStorageTeleport = config.getBoolean("canStorageTeleport");
|
||||
if (!canStorageTeleport) plugin().log(" Storage holder teleportation is disabled.");
|
||||
|
||||
stopHopperDupe = config.getBoolean("stopHopperDupe");
|
||||
if (stopHopperDupe) plugin().log(" Stop Hopper self-feeding Dupe is enabled.");
|
||||
|
||||
stopRailDupe = config.getBoolean("stopRailDupe", true);
|
||||
if (stopRailDupe) plugin().log(" Stop Rail Dupe is enabled.");
|
||||
|
||||
stopEndPortalDeletion = config.getBoolean("stopEndPortalDeletion", true);
|
||||
if (stopEndPortalDeletion) plugin().log(" Stop End Portal Deletion is enabled.");
|
||||
|
||||
stopBedBombing = config.getBoolean("stopBedBombingInHellBiomes", true);
|
||||
if (stopBedBombing) plugin().log(" Stop Bed Bombing In Hell Biomes is enabled.");
|
||||
|
||||
stopAnchorBombing = config.getBoolean("stopAnchorBombing", true);
|
||||
if (stopAnchorBombing) plugin().log("Stop Anchor bombing outside the Nether is enabled");
|
||||
|
||||
preventTreeWrap = config.getBoolean("preventTreeWraparound", true);
|
||||
if (preventTreeWrap) plugin().log(" Stop tree wrapping into bedrock is enabled.");
|
||||
|
||||
maintainFlatBedrock = config.getBoolean("maintainFlatBedrock", false);
|
||||
if (maintainFlatBedrock) plugin().log(" Maintaining bedrock flatness.");
|
||||
|
||||
fixPearlGlitch = config.getBoolean("fixPearlGlitch", false);
|
||||
if (fixPearlGlitch) plugin().log(" Pearl glitch fix enabled.");
|
||||
|
||||
preventLongSigns = config.getBoolean("preventLongSigns", true);
|
||||
signLengthLimit = config.getInt("signLengthLimit", 100);
|
||||
preventLongSignsAbsolute = config.getBoolean("preventLongSignsAbsolute", true);
|
||||
cancelLongSignEvent = config.getBoolean("cancelLongSignEvent", false);
|
||||
hardLimitBookPageSize = config.getBoolean("hardLimitBookPageCount", true);
|
||||
}
|
||||
|
||||
private void wireUpArrays() {
|
||||
bfArray = new ArrayList<>();
|
||||
railArray = new ArrayList<>();
|
||||
pistonArray = new ArrayList<>();
|
||||
|
||||
railArray.add(Material.RAIL);
|
||||
railArray.add(Material.ACTIVATOR_RAIL);
|
||||
railArray.add(Material.DETECTOR_RAIL);
|
||||
railArray.add(Material.POWERED_RAIL);
|
||||
railArray.add(Material.WHITE_CARPET);
|
||||
railArray.add(Material.RED_CARPET);
|
||||
railArray.add(Material.BLACK_CARPET);
|
||||
railArray.add(Material.BLUE_CARPET);
|
||||
railArray.add(Material.BROWN_CARPET);
|
||||
railArray.add(Material.CYAN_CARPET);
|
||||
railArray.add(Material.GRAY_CARPET);
|
||||
railArray.add(Material.GREEN_CARPET);
|
||||
railArray.add(Material.LIGHT_BLUE_CARPET);
|
||||
railArray.add(Material.LIGHT_GRAY_CARPET);
|
||||
railArray.add(Material.LIME_CARPET);
|
||||
railArray.add(Material.YELLOW_CARPET);
|
||||
railArray.add(Material.PURPLE_CARPET);
|
||||
railArray.add(Material.PINK_CARPET);
|
||||
railArray.add(Material.ORANGE_CARPET);
|
||||
railArray.add(Material.MAGENTA_CARPET);
|
||||
|
||||
bfArray.add(BlockFace.NORTH);
|
||||
bfArray.add(BlockFace.SOUTH);
|
||||
bfArray.add(BlockFace.EAST);
|
||||
bfArray.add(BlockFace.WEST);
|
||||
bfArray.add(BlockFace.UP);
|
||||
bfArray.add(BlockFace.DOWN);
|
||||
|
||||
pistonArray.add(Material.PISTON);
|
||||
pistonArray.add(Material.PISTON_HEAD);
|
||||
pistonArray.add(Material.MOVING_PISTON);
|
||||
pistonArray.add(Material.STICKY_PISTON);
|
||||
}
|
||||
|
||||
public boolean isBlockElytraBreakBug() {
|
||||
return blockElytraBreakBug;
|
||||
}
|
||||
|
||||
public double getDamageOnElytraBreakBug() {
|
||||
return damageOnElytraBreakBug;
|
||||
}
|
||||
|
||||
public boolean canStorageTeleport() {
|
||||
return canStorageTeleport;
|
||||
}
|
||||
|
||||
public boolean isStopHopperDupe() {
|
||||
return stopHopperDupe;
|
||||
}
|
||||
|
||||
public boolean isStopRailDupe() {
|
||||
return stopRailDupe;
|
||||
}
|
||||
|
||||
public boolean isStopEndPortalDeletion() {
|
||||
return stopEndPortalDeletion;
|
||||
}
|
||||
|
||||
public ArrayList<BlockFace> getBfArray() {
|
||||
return bfArray;
|
||||
}
|
||||
|
||||
public ArrayList<Material> getRailArray() {
|
||||
return railArray;
|
||||
}
|
||||
|
||||
public ArrayList<Material> getPistonArray() {
|
||||
return pistonArray;
|
||||
}
|
||||
|
||||
public boolean stopBedBombing() {
|
||||
return this.stopBedBombing;
|
||||
}
|
||||
|
||||
public boolean stopAnchorBombing() {
|
||||
return this.stopAnchorBombing;
|
||||
}
|
||||
|
||||
public boolean stopTreeWraparound() {
|
||||
return preventTreeWrap;
|
||||
}
|
||||
|
||||
public boolean hardLimitBookPageSize() {
|
||||
return hardLimitBookPageSize;
|
||||
}
|
||||
|
||||
public boolean maintainFlatBedrock() {
|
||||
return maintainFlatBedrock;
|
||||
}
|
||||
|
||||
public boolean fixPearlGlitch() {
|
||||
return fixPearlGlitch;
|
||||
}
|
||||
|
||||
public boolean isPreventLongSigns() {
|
||||
return preventLongSigns;
|
||||
}
|
||||
|
||||
public int getSignLengthLimit() {
|
||||
return signLengthLimit;
|
||||
}
|
||||
|
||||
public boolean isPreventLongSignsAbsolute() {
|
||||
return preventLongSignsAbsolute;
|
||||
}
|
||||
|
||||
public boolean isCancelLongSignEvent() {
|
||||
return cancelLongSignEvent;
|
||||
}
|
||||
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Holds configurations for the GameTuning module.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class GameTuningConfig extends SimpleHackConfig {
|
||||
|
||||
private boolean chunkLimitsEnabled;
|
||||
private Map<Material, Integer> blockEntityLimits;
|
||||
private Set<UUID> exemptFromLimits;
|
||||
private String chunkLimitsExceededMessage;
|
||||
|
||||
private boolean daytimeBedEnabled;
|
||||
private String daytimeBedSpawnSetMessage;
|
||||
|
||||
private boolean oneToOneNether;
|
||||
private boolean returnNetherPortal;
|
||||
private boolean allowNetherTravel;
|
||||
|
||||
private boolean chestedMinecartInventories;
|
||||
private boolean hopperMinecartInventories;
|
||||
private boolean enderChestInventories;
|
||||
|
||||
private boolean stopTrapHorses;
|
||||
private boolean killTrapHorses;
|
||||
|
||||
private boolean changeSpawnerType;
|
||||
|
||||
private boolean allowVillagerTrading;
|
||||
|
||||
private boolean enderGrief;
|
||||
private boolean witherGrief;
|
||||
private boolean dragonGrief;
|
||||
|
||||
private boolean preventFallingThroughBedrock;
|
||||
|
||||
private boolean badOmen;
|
||||
|
||||
private boolean rainReduction;
|
||||
private double rainOccurrenceChance;
|
||||
|
||||
private Set<Material> noPlace;
|
||||
|
||||
public GameTuningConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
ConfigurationSection chunkLimits = config.getConfigurationSection("chunkLimits");
|
||||
wireupChunkLimits(chunkLimits);
|
||||
|
||||
ConfigurationSection daytimeBed = config.getConfigurationSection("daytimeBed");
|
||||
wireupDaytimeBed(daytimeBed);
|
||||
|
||||
ConfigurationSection rainReduction = config.getConfigurationSection("rainReduction");
|
||||
wireupRainReduction(rainReduction);
|
||||
|
||||
this.oneToOneNether = config.getBoolean("oneToOneNether", false);
|
||||
if (oneToOneNether) plugin().log("One to One Nether is enabled.");
|
||||
|
||||
this.returnNetherPortal = config.getBoolean("returnNetherPortal", true);
|
||||
if (!returnNetherPortal) plugin().log("Return Nether Portals disabled.");
|
||||
|
||||
this.allowNetherTravel = config.getBoolean("allowNetherTravel", false);
|
||||
if (!allowNetherTravel) plugin().log("Nether travel disabled.");
|
||||
|
||||
this.chestedMinecartInventories = config.getBoolean("chestedMinecartInventories", true);
|
||||
if (!chestedMinecartInventories) plugin().log("Chested Minecart Inventories are disabled.");
|
||||
|
||||
this.hopperMinecartInventories = config.getBoolean("hopperMinecartInventories", true);
|
||||
if (!hopperMinecartInventories) plugin().log("Hopper Minecart Inventories are disabled.");
|
||||
|
||||
this.enderChestInventories = config.getBoolean("enderChestInventories", false);
|
||||
if (!enderChestInventories) plugin().log("Ender chest inventories are disabled.");
|
||||
|
||||
this.stopTrapHorses = config.getBoolean("stopTrapHorses", true);
|
||||
if (stopTrapHorses) plugin().log("Stopping trap horses from being annoying.");
|
||||
|
||||
this.killTrapHorses = config.getBoolean("killTrapHorses", true);
|
||||
if (killTrapHorses) plugin().log("Killing trap horses as well");
|
||||
|
||||
this.changeSpawnerType = config.getBoolean("changeSpawnerType", false);
|
||||
if (!changeSpawnerType) plugin().log("Spawner type changing disabled");
|
||||
|
||||
this.allowVillagerTrading = config.getBoolean("allowVillagerTrading", false);
|
||||
if (!allowVillagerTrading) plugin().log("Villager trading disabled");
|
||||
|
||||
this.enderGrief = config.getBoolean("enderGrief", false);
|
||||
if (!enderGrief) plugin().log("Ender grief is disabled.");
|
||||
|
||||
this.witherGrief = config.getBoolean("witherGrief", false);
|
||||
if (!witherGrief) plugin().log("Wither grief is disabled.");
|
||||
|
||||
this.dragonGrief = config.getBoolean("dragonGrief", true);
|
||||
if (!dragonGrief) plugin().log("Dragon grief is disabled.");
|
||||
|
||||
this.preventFallingThroughBedrock = config.getBoolean("preventFallingThroughBedrock", true);
|
||||
|
||||
this.badOmen = config.getBoolean("badOmen", false);
|
||||
if (!badOmen) plugin().log("Bad Omen effect is disabled.");
|
||||
|
||||
noPlace = new HashSet<>();
|
||||
if(config.isList("noplace")) {
|
||||
for(String entry : config.getStringList("noplace")) {
|
||||
try {
|
||||
noPlace.add(Material.valueOf(entry));
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
plugin().log(Level.WARNING, "Material " + entry + " at " + config.getCurrentPath() + " could not be parsed");
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add additional tuning config grabs here. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Wireup for Chunk Limits configuration
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
private void wireupChunkLimits(ConfigurationSection config) {
|
||||
this.blockEntityLimits = new HashMap<>();
|
||||
this.exemptFromLimits = new HashSet<>();
|
||||
this.chunkLimitsEnabled = false;
|
||||
if (config == null) return;
|
||||
|
||||
this.chunkLimitsEnabled = config.getBoolean("enabled", false);
|
||||
this.chunkLimitsExceededMessage = ChatColor.translateAlternateColorCodes('&',
|
||||
config.getString("exceededMessage",
|
||||
ChatColor.RED + "Limit for this chunk reached, you cannot place that! Use a different block."));
|
||||
|
||||
// for each "chunkLimits.tileEntities: " entry, record limit.
|
||||
ConfigurationSection tileEntities = config.getConfigurationSection("tileEntities");
|
||||
for (String key : tileEntities.getKeys(false)) {
|
||||
int limit = tileEntities.getInt(key);
|
||||
Material toBlock = Material.getMaterial(key);
|
||||
if (toBlock == null) continue;
|
||||
|
||||
this.blockEntityLimits.put(toBlock, limit);
|
||||
plugin().log(Level.INFO, " Limiting {0} to {1} per chunk", toBlock.toString(), limit);
|
||||
}
|
||||
|
||||
// for each "chunkLimits.exempt: " entry, record limit.
|
||||
List<String> exempts = config.getStringList("exempt");
|
||||
for (String exempt : exempts) {
|
||||
UUID pExempt = null;
|
||||
try {
|
||||
pExempt = UUID.fromString(exempt);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
pExempt = null;
|
||||
}
|
||||
if (pExempt == null) {
|
||||
OfflinePlayer ofp = Bukkit.getOfflinePlayer(exempt);
|
||||
if (ofp != null) {
|
||||
pExempt = ofp.getUniqueId();
|
||||
}
|
||||
}
|
||||
if (pExempt == null) {
|
||||
plugin().log(Level.INFO, " Unable to exempt {0}, player not found", exempt);
|
||||
} else {
|
||||
plugin().log(Level.INFO, " Adding limits exemption for {0} as {1}", exempt, pExempt);
|
||||
this.exemptFromLimits.add(pExempt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wireup for enabling setting your spawn during the day.
|
||||
*
|
||||
* @author Amelorate
|
||||
*/
|
||||
private void wireupDaytimeBed(ConfigurationSection config) {
|
||||
if (config == null) {
|
||||
this.daytimeBedEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.daytimeBedEnabled = config.getBoolean("enabled", false);
|
||||
this.daytimeBedSpawnSetMessage = ChatColor.translateAlternateColorCodes('&',
|
||||
config.getString("spawnSetMessage", ChatColor.GRAY + "Your spawn has been set."));
|
||||
}
|
||||
|
||||
private void wireupRainReduction(ConfigurationSection config) {
|
||||
if (config == null) {
|
||||
this.rainReduction = false;
|
||||
return;
|
||||
}
|
||||
this.rainReduction = config.getBoolean("enabled", false);
|
||||
this.rainOccurrenceChance = config.getDouble("rainOccurrenceChance");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true / false if chunk limits are on
|
||||
*/
|
||||
public boolean areChunkLimitsEnabled() {
|
||||
return this.chunkLimitsEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the chunk limit for a specified material.
|
||||
* Returns null if no limit is set.
|
||||
*
|
||||
* @param mat the Material to return a limit on, if set.
|
||||
* @return the max # per chunk, or null if no limit set.
|
||||
*/
|
||||
public Integer getChunkLimit(Material mat) {
|
||||
return this.chunkLimitsEnabled ? this.blockEntityLimits.get(mat) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if the supplied UUID is exempt from limits.
|
||||
*
|
||||
* @param player the UUID to check
|
||||
* @return false it the player is exempt, true otherwise.
|
||||
*/
|
||||
public boolean applyChunkLimits(UUID player) {
|
||||
return this.chunkLimitsEnabled ? !this.exemptFromLimits.contains(player) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the generic limit message. TODO: Replace with customized message tailored per player.
|
||||
*/
|
||||
public String getChunkLimitsExceededMessage() {
|
||||
return this.chunkLimitsExceededMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The message that is sent to the player if they right click on a bed and set their spawn.
|
||||
* Empty string if there should not be a message, and null if daytime beds are disabled.
|
||||
*/
|
||||
public String getDaytimeBedSpawnSetMessage() {
|
||||
return daytimeBedEnabled ? daytimeBedSpawnSetMessage : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If setting your spawn with a bed during the daytime is enabled.
|
||||
*/
|
||||
public boolean areDaytimeBedsEnabled() {
|
||||
return daytimeBedEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If one to one nether is enabled.
|
||||
*/
|
||||
public boolean isOneToOneNether() {
|
||||
return oneToOneNether;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If return portals are enabled.
|
||||
*/
|
||||
public boolean isReturnNetherPortal() {
|
||||
return returnNetherPortal;
|
||||
}
|
||||
|
||||
public boolean allowNetherTravel() {
|
||||
return allowNetherTravel;
|
||||
}
|
||||
|
||||
public boolean isChestedMinecartInventories() {
|
||||
return chestedMinecartInventories;
|
||||
}
|
||||
|
||||
public boolean isHopperMinecartInventories() {
|
||||
return hopperMinecartInventories;
|
||||
}
|
||||
|
||||
public boolean isEnderChestInventories() {
|
||||
return enderChestInventories;
|
||||
}
|
||||
|
||||
public boolean stopTrapHorses() {
|
||||
return stopTrapHorses;
|
||||
}
|
||||
|
||||
public boolean killTrapHorses() {
|
||||
return killTrapHorses;
|
||||
}
|
||||
|
||||
public boolean canChangeSpawnerType() {
|
||||
return changeSpawnerType;
|
||||
}
|
||||
|
||||
public boolean allowVillagerTrading() {
|
||||
return allowVillagerTrading;
|
||||
}
|
||||
|
||||
public boolean isEnderGrief() {
|
||||
return enderGrief;
|
||||
}
|
||||
|
||||
public boolean isWitherGrief() {
|
||||
return witherGrief;
|
||||
}
|
||||
|
||||
public boolean isDragonGrief() {
|
||||
return dragonGrief;
|
||||
}
|
||||
|
||||
public boolean isPreventFallingThroughBedrock() {
|
||||
return preventFallingThroughBedrock;
|
||||
}
|
||||
|
||||
public boolean isBadOmenEnabled() {
|
||||
return badOmen;
|
||||
}
|
||||
|
||||
public boolean isRainReductionEnabled() {
|
||||
return rainReduction;
|
||||
}
|
||||
|
||||
public double getRainOccurrenceChance() {
|
||||
return rainOccurrenceChance;
|
||||
}
|
||||
|
||||
public boolean canPlace(Material mat) {
|
||||
return !noPlace.contains(mat);
|
||||
}
|
||||
|
||||
public Map<Material, Integer> getBlockEntityLimits() {
|
||||
return blockEntityLimits;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public class HorseStatsConfig extends SimpleHackConfig {
|
||||
|
||||
private Material horseCheckerItem;
|
||||
|
||||
public HorseStatsConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
horseCheckerItem = Material.getMaterial(config.getString("wand"));
|
||||
}
|
||||
|
||||
public Material getHorseCheckerItem() {
|
||||
return horseCheckerItem;
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.List;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Define an "into" list of Strings where the Strings are event classpaths.
|
||||
* Can monitor not only bukkit events but also plugin / custom events; just give the
|
||||
* valid classpath.
|
||||
*
|
||||
* This bypasses the "safe" bukkit way of registering listeners for events. So it
|
||||
* also bypasses Timings.
|
||||
*
|
||||
* This is the only warning I'll give. Be careful with this and prefer to leave it off.
|
||||
*
|
||||
* Wireups only happen on restart, I'm dubious about injecting live for now.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*
|
||||
*/
|
||||
public class InsightConfig extends SimpleHackConfig {
|
||||
private List<String> insightOn;
|
||||
|
||||
public InsightConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
if (config.contains("into")) {
|
||||
insightOn = config.getStringList("into");
|
||||
} else {
|
||||
insightOn = null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getInsightOn() {
|
||||
return insightOn;
|
||||
}
|
||||
}
|
||||
+39
-26
@@ -1,26 +1,24 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BookMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
|
||||
|
||||
/**
|
||||
* Simple Config wrapper for Introbook specification.
|
||||
*
|
||||
* @author ProgrammerDan <programmerdan@gmail.com>
|
||||
* @author ProgrammerDan programmerdan@gmail.com
|
||||
*/
|
||||
public class IntrobookConfig extends SimpleHackConfig {
|
||||
|
||||
|
||||
/**
|
||||
* The title of the book
|
||||
*/
|
||||
@@ -38,11 +36,11 @@ public class IntrobookConfig extends SimpleHackConfig {
|
||||
* just drops.
|
||||
*/
|
||||
private boolean follow;
|
||||
|
||||
|
||||
public IntrobookConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
|
||||
public IntrobookConfig(ConfigurationSection base) {
|
||||
super(SimpleAdminHacks.instance(), base);
|
||||
}
|
||||
@@ -52,26 +50,26 @@ public class IntrobookConfig extends SimpleHackConfig {
|
||||
this.title = config.getString("contents.title");
|
||||
this.author = config.getString("contents.author");
|
||||
List<String> tPages = config.getStringList("contents.pages");
|
||||
|
||||
|
||||
if (this.title != null) {
|
||||
this.title = ChatColor.translateAlternateColorCodes('&', this.title);
|
||||
} else {
|
||||
this.setEnabled(false);
|
||||
setShouldEnable(false);
|
||||
plugin().log("Introbook disabled, no title given");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (this.author != null) {
|
||||
this.author = ChatColor.translateAlternateColorCodes('&', this.author);
|
||||
}
|
||||
|
||||
|
||||
if (tPages != null && tPages.size() > 0) {
|
||||
this.pages = new ArrayList<String>(tPages.size());
|
||||
for (String page : tPages) {
|
||||
this.pages.add(ChatColor.translateAlternateColorCodes('&', page));
|
||||
}
|
||||
} else {
|
||||
this.setEnabled(false);
|
||||
setShouldEnable(false);
|
||||
plugin().log("Introbook disabled, no pages");
|
||||
return;
|
||||
}
|
||||
@@ -82,41 +80,56 @@ public class IntrobookConfig extends SimpleHackConfig {
|
||||
*
|
||||
* @return ItemStack containing the book.
|
||||
*/
|
||||
public ItemStack getIntroBook() {
|
||||
public ItemStack getIntroBook(Player p) {
|
||||
ItemStack is = new ItemStack(Material.WRITTEN_BOOK);
|
||||
BookMeta bm = (BookMeta) is.getItemMeta();
|
||||
bm.setTitle(this.title);
|
||||
if (p == null) {
|
||||
bm.setTitle(this.title.replaceAll("\\$\\{player\\}", ""));
|
||||
} else {
|
||||
bm.setTitle(this.title.replaceAll("\\$\\{player\\}", p.getName()));
|
||||
}
|
||||
bm.setAuthor(this.author);
|
||||
bm.setPages(this.pages);
|
||||
ArrayList<String> alist = null;
|
||||
if (p == null) {
|
||||
alist = new ArrayList<String>(this.pages);
|
||||
} else {
|
||||
alist = new ArrayList<String>();
|
||||
for (String page : this.pages) {
|
||||
alist.add(page.replaceAll("\\$\\{player\\}", p.getName()));
|
||||
}
|
||||
}
|
||||
bm.setPages(alist);
|
||||
is.setItemMeta(bm);
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
public boolean isIntroBook(ItemStack is) {
|
||||
if (Material.WRITTEN_BOOK != is.getType()) return false;
|
||||
|
||||
|
||||
ItemMeta meta = is.getItemMeta();
|
||||
if (!(meta instanceof BookMeta)) return false;
|
||||
|
||||
|
||||
BookMeta book = (BookMeta) meta;
|
||||
if (!(getTitle().equals(book.getTitle()))) return false;
|
||||
if (!(getTitle().contains(
|
||||
book.getTitle().replaceAll("\\$\\{player\\}", "")
|
||||
))) return false;
|
||||
if (!(getAuthor().equals(book.getAuthor()))) return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public boolean doesFollow() {
|
||||
return this.follow;
|
||||
}
|
||||
|
||||
|
||||
public String getTitle(){
|
||||
return this.title;
|
||||
}
|
||||
|
||||
|
||||
public String getAuthor() {
|
||||
return this.author;
|
||||
}
|
||||
|
||||
|
||||
public List<String> getPages() {
|
||||
return new ArrayList<String>(this.pages);
|
||||
}
|
||||
+2
-3
@@ -1,9 +1,8 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Stub; this hack just turns on and off, and has some commands.
|
||||
+20
-13
@@ -1,16 +1,14 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.BroadcastLevel;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.BroadcastLevel;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHackConfig;
|
||||
|
||||
/**
|
||||
* Some simple new player related configuration options.
|
||||
* Might have overlap with other plugins at some point (CivMenu, looking at you)
|
||||
@@ -22,7 +20,7 @@ public class NewfriendAssistConfig extends SimpleHackConfig {
|
||||
/**
|
||||
* What should I send to people when I announce a newfriend?
|
||||
*/
|
||||
private String announceMessage = "&%Player% is brand new!";
|
||||
private String announceMessage;
|
||||
/**
|
||||
* Who should I broadcast to?
|
||||
*/
|
||||
@@ -35,21 +33,25 @@ public class NewfriendAssistConfig extends SimpleHackConfig {
|
||||
* What is the newbie kit composed of.
|
||||
*/
|
||||
private ItemStack[] newbieKit;
|
||||
|
||||
/**
|
||||
* Should we give a kit to people who respawn without a bed/anchor?
|
||||
*/
|
||||
private boolean giveToRandomSpawners;
|
||||
|
||||
//private List<HelpTips> helps; // TODO
|
||||
|
||||
public NewfriendAssistConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
|
||||
public NewfriendAssistConfig(ConfigurationSection base) {
|
||||
super(SimpleAdminHacks.instance(), base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.announceMessage = config.getString("announce.message", announceMessage);
|
||||
|
||||
this.announceMessage = config.getString("announce", "&f%Player% is brand new!");
|
||||
|
||||
List<String> broadcastTo = config.getStringList("broadcast");
|
||||
if (this.announceBroadcast == null) {
|
||||
this.announceBroadcast = new LinkedList<BroadcastLevel>();
|
||||
@@ -58,7 +60,7 @@ public class NewfriendAssistConfig extends SimpleHackConfig {
|
||||
for (String type : broadcastTo) {
|
||||
try {
|
||||
this.announceBroadcast.add(BroadcastLevel.valueOf(type));
|
||||
|
||||
|
||||
plugin().log(Level.INFO, " broadcast: {0}", type);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// noop
|
||||
@@ -80,8 +82,9 @@ public class NewfriendAssistConfig extends SimpleHackConfig {
|
||||
} else {
|
||||
plugin().log(Level.INFO, " introkit disabled");
|
||||
}
|
||||
this.giveToRandomSpawners = config.getBoolean("giveIntroKitToRandomSpawners", true);
|
||||
}
|
||||
|
||||
|
||||
public List<BroadcastLevel> getAnnounceBroadcast() {
|
||||
return announceBroadcast;
|
||||
}
|
||||
@@ -93,8 +96,12 @@ public class NewfriendAssistConfig extends SimpleHackConfig {
|
||||
public boolean isIntroKitEnabled() {
|
||||
return hasNewbieKit;
|
||||
}
|
||||
|
||||
|
||||
public ItemStack[] getIntroKit() {
|
||||
return newbieKit;
|
||||
}
|
||||
|
||||
public boolean giveToRandomSpawners() {
|
||||
return giveToRandomSpawners;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public class ReinforcedChestBreakConfig extends SimpleHackConfig{
|
||||
|
||||
/**
|
||||
* This is the delay between messages
|
||||
*/
|
||||
private int delay;
|
||||
|
||||
/**
|
||||
* The message if someone is raiding a reinforced chest
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public ReinforcedChestBreakConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.delay = config.getInt("delay", 180);
|
||||
this.message = config.getString("message", "&4%player% is raiding a chest at %x% %y% %z%.");
|
||||
}
|
||||
|
||||
public int getDelay() {
|
||||
return delay;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public class SanityHackConfig extends SimpleHackConfig {
|
||||
|
||||
private boolean trackPlace; //Track block placed
|
||||
private boolean trackBreak; //Track block broken
|
||||
//private boolean trackOpen; //Track block opened (chest)
|
||||
private int belowYLevel; //Track things below this y level
|
||||
|
||||
public SanityHackConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.trackPlace = config.getBoolean("trackPlace", true);
|
||||
plugin().log(Level.INFO, "Tracking placement: {0}", this.trackPlace);
|
||||
|
||||
this.trackBreak = config.getBoolean("trackBreak", true);
|
||||
plugin().log(Level.INFO, "Tracking breaking: {0}", this.trackBreak);
|
||||
|
||||
/*this.trackOpen = config.getBoolean("trackOpen", false);
|
||||
plugin().log(Level.INFO, "Tracking opening: {0}", this.trackOpen);*/
|
||||
|
||||
this.belowYLevel = config.getInt("belowYLevel", 7);
|
||||
plugin().log(Level.INFO, "Tracking below Y: {0}", this.belowYLevel);
|
||||
}
|
||||
|
||||
public boolean isTrackingPlace(){
|
||||
return this.trackPlace;
|
||||
}
|
||||
|
||||
public boolean isTrackingBreak(){
|
||||
return this.trackBreak;
|
||||
}
|
||||
|
||||
/*public boolean isTrackingOpen(){
|
||||
return this.trackOpen;
|
||||
}*/
|
||||
|
||||
public int getTrackingLevel(){
|
||||
return this.belowYLevel;
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public class TimingsHackConfig extends SimpleHackConfig {
|
||||
|
||||
private Integer timingsMap;
|
||||
private Map<String, Integer> bindMaps;
|
||||
private Map<Integer, String> reverseBindMaps;
|
||||
|
||||
public TimingsHackConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
timingsMap = config.contains("timingMap") ? config.getInt("timingMap") : null;
|
||||
bindMaps = new ConcurrentHashMap<>();
|
||||
reverseBindMaps = new ConcurrentHashMap<>();
|
||||
if (config.contains("bindings")) {
|
||||
ConfigurationSection bindings = config.getConfigurationSection("bindings");
|
||||
Set<String> keys = bindings.getKeys(false);
|
||||
for (String key : keys) {
|
||||
bindMaps.put(key, bindings.getInt(key));
|
||||
reverseBindMaps.put(bindings.getInt(key), key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getTimingsMap() {
|
||||
return timingsMap;
|
||||
}
|
||||
|
||||
public void setTimingsMap(int mapId) {
|
||||
timingsMap = mapId;
|
||||
getBase().set("timingMap", mapId);
|
||||
}
|
||||
|
||||
public Integer getBindMap(String bind) {
|
||||
if (bind == null) {
|
||||
return null;
|
||||
}
|
||||
return bindMaps.get(bind);
|
||||
}
|
||||
|
||||
public void setBindMap(String bind, int mapId) {
|
||||
Integer prior = bindMaps.replace(bind, mapId);
|
||||
if (prior != null) {
|
||||
reverseBindMaps.remove(prior);
|
||||
}
|
||||
reverseBindMaps.replace(mapId, bind);
|
||||
getBase().set("bindings." + bind, mapId);
|
||||
}
|
||||
|
||||
public String getBindFromId(int mapId) {
|
||||
return reverseBindMaps.get(mapId);
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.configs;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public class ToggleLampConfig extends SimpleHackConfig {
|
||||
|
||||
private long cooldownTime;
|
||||
|
||||
public ToggleLampConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(ConfigurationSection config) {
|
||||
this.cooldownTime = config.getLong("cooldownTime", 100);
|
||||
}
|
||||
|
||||
public long getCooldownTime() {
|
||||
return this.cooldownTime;
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public abstract class BasicHack extends SimpleHack<BasicHackConfig> implements Listener {
|
||||
|
||||
public BasicHack(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
// REMEMBER TO CALL SUPER
|
||||
@Override
|
||||
public void onEnable() {
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
|
||||
// REMEMBER TO CALL SUPER
|
||||
@Override
|
||||
public void onDisable() {
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
// YOU DON'T HAVE TO COPY THIS! It's inherited.
|
||||
public static BasicHackConfig generate(final SimpleAdminHacks plugin, final ConfigurationSection config) {
|
||||
return new BasicHackConfig(plugin, config);
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Use this when your hack either doesn't have any config values, or you're loading all your values though
|
||||
* {@link AutoLoad}. If you want to extend this, extend {@link SimpleHackConfig} directly.
|
||||
*/
|
||||
public final class BasicHackConfig extends SimpleHackConfig {
|
||||
|
||||
public BasicHackConfig(final SimpleAdminHacks plugin, final ConfigurationSection base) {
|
||||
super(plugin, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void wireup(final ConfigurationSection config) { }
|
||||
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.reflect.ClassPath;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.exceptions.InvalidConfigException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public final class HackManager {
|
||||
|
||||
private static final String HACKS_PATH = "com.programmerdan.minecraft.simpleadminhacks.hacks";
|
||||
|
||||
private final SimpleAdminHacks plugin;
|
||||
private final List<SimpleHack<?>> hacks;
|
||||
|
||||
public HackManager(final SimpleAdminHacks plugin) {
|
||||
this.plugin = plugin;
|
||||
this.hacks = new LinkedList<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnstableApiUsage", "unchecked"})
|
||||
public void loadAllHacks() {
|
||||
// Now load all the Hacks and register.
|
||||
final ConfigurationSection hackConfigs = plugin.getConfig().getConfigurationSection("hacks");
|
||||
if (hackConfigs == null) {
|
||||
this.plugin.warning("There are no hacks defined under 'hacks' the config. Is this right?");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final ClassPath getSamplersPath = ClassPath.from(plugin.exposeClassLoader());
|
||||
for (final var classInfo : getSamplersPath.getTopLevelClassesRecursive(HACKS_PATH)) {
|
||||
try {
|
||||
final Class<?> clazz = classInfo.load();
|
||||
if (clazz == null || !SimpleHack.class.isAssignableFrom(clazz)) {
|
||||
continue;
|
||||
}
|
||||
this.plugin.info("Found hack class [" + clazz.getName() + "]");
|
||||
loadHack((Class<SimpleHack<?>>) clazz, hackConfigs.getConfigurationSection(clazz.getSimpleName()));
|
||||
}
|
||||
catch (final NoClassDefFoundError exception) {
|
||||
this.plugin.warning("Unable to load hack \"" + classInfo.getSimpleName() + "\" probably due to a " +
|
||||
"dependency / import error.", exception);
|
||||
//continue;
|
||||
}
|
||||
catch (final Exception exception) {
|
||||
this.plugin.warning("Failed to complete hack discovery of: " + classInfo.getName(), exception);
|
||||
//continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (final Exception exception) {
|
||||
this.plugin.warning("Failed to complete hack registration");
|
||||
exception.printStackTrace();
|
||||
return;
|
||||
}
|
||||
if (this.hacks.isEmpty()) {
|
||||
this.plugin.warning("No hacks have been loaded.");
|
||||
//return;
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleHack<?> loadHack(final Class<SimpleHack<?>> hackClass, final ConfigurationSection config) {
|
||||
Preconditions.checkNotNull(hackClass, "Hack class cannot be null!");
|
||||
if (config == null) {
|
||||
this.plugin.warning("Config for \"" + hackClass.getSimpleName() + "\" not defined, skipping.");
|
||||
return null;
|
||||
}
|
||||
final String hackName = hackClass.getSimpleName();
|
||||
SimpleHackConfig hackConfig;
|
||||
try {
|
||||
hackConfig = (SimpleHackConfig) MethodUtils.invokeExactStaticMethod(hackClass,"generate",
|
||||
new Object[] { this.plugin, config },
|
||||
new Class[] { SimpleAdminHacks.class, ConfigurationSection.class });
|
||||
}
|
||||
catch (final NoSuchMethodException exception) {
|
||||
this.plugin.warning("Could not find config generator for \"" + hackName + "\", skipping.");
|
||||
return null;
|
||||
}
|
||||
catch (final IllegalAccessException exception) {
|
||||
this.plugin.warning("Could not access config generator for \"" + hackName + "\", skipping.");
|
||||
exception.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
catch (final IllegalArgumentException exception) {
|
||||
this.plugin.warning("Config generator for \"" + hackName + "\" threw an argument exception, skipping.");
|
||||
exception.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
catch (final InvocationTargetException exception) {
|
||||
this.plugin.warning("Config generator for \"" + hackName + "\" threw an invocation target exception, " +
|
||||
"skipping.");
|
||||
exception.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
if (hackConfig == null) {
|
||||
this.plugin.warning("Config generator for \"" + hackName + "\" returned nothing, skipping.");
|
||||
return null;
|
||||
}
|
||||
final var configClass = hackConfig.getClass();
|
||||
if (configClass.isAnonymousClass()) {
|
||||
this.plugin.warning("Config for \"" + hackName + "\" is anonymous, skipping.");
|
||||
return null;
|
||||
}
|
||||
this.plugin.info("Config for \"" + hackName + "\" found; instance [" + hackConfig.toString() + "]");
|
||||
SimpleHack<?> hack;
|
||||
try {
|
||||
hack = hackClass.getConstructor(SimpleAdminHacks.class, configClass).newInstance(this.plugin, hackConfig);
|
||||
}
|
||||
catch (final InvalidConfigException exception) {
|
||||
this.plugin.warning("Failed to initialise \"" + hackName + "\"'s configuration", exception);
|
||||
return null;
|
||||
}
|
||||
catch (final Exception exception) {
|
||||
this.plugin.warning("Failed to initialise \"" + hackName + "\"", exception);
|
||||
return null;
|
||||
}
|
||||
register(hack);
|
||||
this.plugin.info("Registered hack: " + hackName);
|
||||
interactWithHack(hack, (finalHack) -> {
|
||||
finalHack.onLoad();
|
||||
if (finalHack.shouldEnable()) {
|
||||
finalHack.enable();
|
||||
}
|
||||
});
|
||||
return hack;
|
||||
}
|
||||
|
||||
public void enableAllHacks() {
|
||||
for (final SimpleHack<?> hack : hacks) {
|
||||
enableHack(hack);
|
||||
}
|
||||
}
|
||||
|
||||
public void enableHack(final SimpleHack<?> hack) {
|
||||
Preconditions.checkNotNull(hack, "Hack cannot be null!");
|
||||
interactWithHack(hack, (ignored) -> {
|
||||
if (!hack.isEnabled()) {
|
||||
hack.enable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void disableAllHacks() {
|
||||
for (final SimpleHack<?> hack : hacks) {
|
||||
disableHack(hack);
|
||||
}
|
||||
}
|
||||
|
||||
public void disableHack(final SimpleHack<?> hack) {
|
||||
Preconditions.checkNotNull(hack, "Hack cannot be null!");
|
||||
interactWithHack(hack, (ignored) -> {
|
||||
if (hack.isEnabled()) {
|
||||
hack.disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new SimpleHack.
|
||||
*/
|
||||
void register(final SimpleHack<?> hack) {
|
||||
this.hacks.add(hack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a wrapped version of hacks preventing external removal but allowing
|
||||
* interaction with the hacks.
|
||||
*/
|
||||
public List<SimpleHack<? extends SimpleHackConfig>> getHacks() {
|
||||
return Collections.unmodifiableList(this.hacks);
|
||||
}
|
||||
|
||||
public SimpleHack<? extends SimpleHackConfig> getHack(final String name) {
|
||||
if (Strings.isNullOrEmpty(name)) {
|
||||
return null;
|
||||
}
|
||||
for (final SimpleHack<? extends SimpleHackConfig> candidate : this.hacks) {
|
||||
if (StringUtils.equalsIgnoreCase(name, candidate.getClass().getSimpleName())) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void interactWithHack(final SimpleHack<?> hack, final Consumer<SimpleHack<?>> processor) {
|
||||
Preconditions.checkNotNull(hack, "Cannot interact with a null hack!");
|
||||
Preconditions.checkNotNull(processor, "Cannot interact with a null processor!");
|
||||
try {
|
||||
processor.accept(hack);
|
||||
}
|
||||
catch (final NoClassDefFoundError exception) {
|
||||
this.plugin.warning("Unable to interact with hack \"" + hack.getClass().getSimpleName() + "\" probably " +
|
||||
"due to a dependency / import error.", exception);
|
||||
}
|
||||
catch (final Exception exception) {
|
||||
this.plugin.warning("Unable to deactivate hack \"" + hack.getClass().getSimpleName() + "\"", exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+249
@@ -0,0 +1,249 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.util.NumberConversions;
|
||||
import vg.civcraft.mc.civmodcore.utilities.CivLogger;
|
||||
|
||||
/**
|
||||
* Baseline structure for a managed hack.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public abstract class SimpleHack<T extends SimpleHackConfig> {
|
||||
|
||||
protected final CivLogger logger;
|
||||
protected final SimpleAdminHacks plugin;
|
||||
protected final T config;
|
||||
private boolean enabled;
|
||||
|
||||
public SimpleHack(final SimpleAdminHacks plugin, final T config) {
|
||||
this.logger = CivLogger.getLogger(getClass());
|
||||
this.plugin = Objects.requireNonNull(plugin, "Plugin cannot be null!");
|
||||
this.config = Objects.requireNonNull(config, "Config cannot be null!");
|
||||
}
|
||||
|
||||
public final SimpleAdminHacks plugin() {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
public final T config() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns true if this hack should be enabled automatically due to its `enabled` config option.
|
||||
*/
|
||||
public boolean shouldEnable() {
|
||||
return this.config.shouldEnable();
|
||||
}
|
||||
|
||||
public final void enable() {
|
||||
this.enabled = true;
|
||||
this.config.setEnabled(true); // Needed for legacy hacks that rely on their config for current states
|
||||
populateAutoLoadFields();
|
||||
onEnable();
|
||||
dataBootstrap();
|
||||
registerCommands();
|
||||
registerListeners();
|
||||
this.plugin.info(ChatColor.AQUA + getName() + " enabled!");
|
||||
}
|
||||
|
||||
public final void disable() {
|
||||
unregisterListeners();
|
||||
unregisterCommands();
|
||||
dataCleanup();
|
||||
onDisable();
|
||||
this.config.setEnabled(false); // Needed for legacy hacks that rely on their config for current states
|
||||
this.enabled = false;
|
||||
this.plugin.info(ChatColor.AQUA + getName() + " disabled!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this hack is loaded.
|
||||
*/
|
||||
public void onLoad() { }
|
||||
|
||||
/**
|
||||
* Called when this hack is enabled.
|
||||
*/
|
||||
public void onEnable() { }
|
||||
|
||||
/**
|
||||
* Called when this hack is disabled.
|
||||
*/
|
||||
public void onDisable() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #onEnable()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void registerListeners() {}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #onEnable()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void registerCommands() {}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #onEnable()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void dataBootstrap() {}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #onDisable()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void unregisterListeners() {}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #onDisable()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void unregisterCommands() {}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #onDisable()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void dataCleanup() {}
|
||||
|
||||
/**
|
||||
* Not optional; customized status for this SimpleHack for display in CnC
|
||||
*/
|
||||
public String status() {
|
||||
final StringBuilder genStatus = new StringBuilder();
|
||||
genStatus.append(this.getClass().getSimpleName());
|
||||
genStatus.append(" is ");
|
||||
if (!isEnabled()) {
|
||||
genStatus.append("disabled");
|
||||
return genStatus.toString();
|
||||
}
|
||||
genStatus.append("enabled\n");
|
||||
for(final Field field : getClass().getDeclaredFields()) {
|
||||
genStatus.append(field.getName());
|
||||
genStatus.append(" = ");
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
genStatus.append(field.get(this));
|
||||
}
|
||||
catch (final IllegalArgumentException | IllegalAccessException exception) {
|
||||
plugin().warning("Failed to read field", exception);
|
||||
}
|
||||
genStatus.append('\n');
|
||||
}
|
||||
return genStatus.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple name equality. Don't have two hacks with the same name please.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if (object instanceof SimpleHack) {
|
||||
final SimpleHack<?> other = (SimpleHack<?>) object;
|
||||
if (StringUtils.equals(getName(), other.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void populateAutoLoadFields() {
|
||||
final Class<?> hackClass = getClass();
|
||||
final ConfigurationSection config = config().getBase();
|
||||
for (final Field field : hackClass.getDeclaredFields()) {
|
||||
final AutoLoad autoLoad = field.getAnnotation(AutoLoad.class);
|
||||
if (autoLoad == null) {
|
||||
continue;
|
||||
}
|
||||
final String hackName = getClass().getSimpleName();
|
||||
final String identifier = Strings.isNullOrEmpty(autoLoad.id()) ? field.getName() : autoLoad.id();
|
||||
// Value type
|
||||
Class<?> clazz;
|
||||
if (field.getType().getName().split("\\.").length == 1) { // TODO: Is this really necessary?
|
||||
clazz = Array.get(Array.newInstance(field.getType(), 1), 0).getClass(); // unwrap primitives
|
||||
}
|
||||
else {
|
||||
clazz = field.getType();
|
||||
}
|
||||
// Value itself
|
||||
Object value;
|
||||
try {
|
||||
// Handle primitives (ints, booleans, and doubles are handled just fine already)
|
||||
if (byte.class.isAssignableFrom(clazz) || Byte.class.isAssignableFrom(clazz)) {
|
||||
value = NumberConversions.toByte(config.getInt(identifier));
|
||||
}
|
||||
else if (short.class.isAssignableFrom(clazz) || Short.class.isAssignableFrom(clazz)) {
|
||||
value = NumberConversions.toShort(config.getInt(identifier));
|
||||
}
|
||||
else if (long.class.isAssignableFrom(clazz) || Long.class.isAssignableFrom(clazz)) {
|
||||
value = config.getLong(identifier);
|
||||
}
|
||||
else if (float.class.isAssignableFrom(clazz) || Float.class.isAssignableFrom(clazz)) {
|
||||
value = NumberConversions.toFloat(config.getDouble(identifier));
|
||||
}
|
||||
else if (char.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz)) {
|
||||
final String temp = config.getString(identifier);
|
||||
value = Strings.isNullOrEmpty(temp) ? 0 : temp.toCharArray()[0];
|
||||
}
|
||||
else {
|
||||
value = config.getObject(identifier, clazz, null);
|
||||
}
|
||||
if (value == null) {
|
||||
// do nothing
|
||||
}
|
||||
else if (List.class.isAssignableFrom(clazz)) {
|
||||
value = ((List<?>) value).stream()
|
||||
.map(autoLoad.processor()::parse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
// TODO: Create a map parser
|
||||
// else if (Map.class.isAssignableFrom(clazz)) { }
|
||||
else {
|
||||
value = autoLoad.processor().parse(value);
|
||||
}
|
||||
}
|
||||
catch (final Exception exception) {
|
||||
throw new IllegalArgumentException("Hack \"" + hackName + "\" failed to read parameter \"" +
|
||||
identifier + "\"", exception);
|
||||
}
|
||||
if (value == null) {
|
||||
this.plugin.warning("Hack \"" + hackName + " has no value for field \"" + identifier + "\"");
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
FieldUtils.writeField(field, this, value, true);
|
||||
}
|
||||
catch (final IllegalArgumentException | IllegalAccessException exception) {
|
||||
throw new IllegalStateException("\"" + clazz.getSimpleName() + "\" in \"" + hackName + "\" could " +
|
||||
"not be set.", exception);
|
||||
}
|
||||
this.plugin.info("Loaded \"" + identifier + "\" = \"" + value + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import java.util.Map;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Simple config shell that assumes a {@link ConfigurationSection} as a base.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public abstract class SimpleHackConfig {
|
||||
|
||||
private final SimpleAdminHacks plugin;
|
||||
private final ConfigurationSection base;
|
||||
private final Map<String, Object> data;
|
||||
private boolean shouldEnable;
|
||||
private boolean enabled; // Legacy support
|
||||
|
||||
/**
|
||||
* Constructor that sets the internal config section. That base config is not visible
|
||||
* outside of this class or its subclasses.
|
||||
*
|
||||
* Also extracts the one shared element of all hack configs, the "name" of the hack.
|
||||
*
|
||||
* Calls {@link #wireup(ConfigurationSection)}
|
||||
*/
|
||||
public SimpleHackConfig(final SimpleAdminHacks plugin, final ConfigurationSection base) {
|
||||
this(plugin, base, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that sets the internal config section. That base config is not visible
|
||||
* outside of this class or its subclasses.
|
||||
*
|
||||
* Also extracts the one shared element of all hack configs, the "name" of the hack.
|
||||
*
|
||||
* Calls {@link #wireup(ConfigurationSection)}
|
||||
*/
|
||||
public SimpleHackConfig(final SimpleAdminHacks plugin, final ConfigurationSection base, final boolean wireup) {
|
||||
this.plugin = plugin;
|
||||
this.base = base;
|
||||
this.data = base.getValues(true);
|
||||
this.shouldEnable = this.enabled = base.getBoolean("enabled", false);
|
||||
this.plugin.info("Config for \"" + base.getName() + "\"; " +
|
||||
"is " + (this.shouldEnable ? "enabled" : "disabled") + "; " +
|
||||
"instance [" + this + "]");
|
||||
if (wireup) {
|
||||
wireup(base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should override this method.
|
||||
*/
|
||||
protected abstract void wireup(final ConfigurationSection config);
|
||||
|
||||
/**
|
||||
* Might be useful in some situations for subclasses to directly access the
|
||||
* stored base config().
|
||||
*/
|
||||
public ConfigurationSection getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
protected SimpleAdminHacks plugin() {
|
||||
if (this.plugin == null) {
|
||||
return SimpleAdminHacks.instance();
|
||||
}
|
||||
else {
|
||||
return this.plugin;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns whether the represented hack should be enabled after being loaded.
|
||||
*/
|
||||
public boolean shouldEnable() {
|
||||
return this.shouldEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configs to prevent / re-allow the represented hack to be enabled after load.
|
||||
*
|
||||
* @param shouldEnable Whether to load the represented hack after being loaded.
|
||||
*/
|
||||
protected void setShouldEnable(final boolean shouldEnable) {
|
||||
this.shouldEnable = shouldEnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link SimpleHack#isEnabled()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link HackManager#enableHack(SimpleHack)} or
|
||||
* {@link HackManager#disableHack(SimpleHack)} instead.
|
||||
*/
|
||||
public void setEnabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean has(final String key) {
|
||||
if (Strings.isNullOrEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
return this.data.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for base config's get, for use with the hacks command
|
||||
*/
|
||||
public Object get(final String key) {
|
||||
if (Strings.isNullOrEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
return this.data.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for base config's set, for use with the hacks command
|
||||
*/
|
||||
public void set(final String key, final Object value) {
|
||||
if (Strings.isNullOrEmpty(key)) {
|
||||
return;
|
||||
}
|
||||
this.data.put(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.autoload;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface AutoLoad {
|
||||
|
||||
//Thanks Angelia
|
||||
|
||||
/**
|
||||
* The identifier used for this option when reading it from the hacks config yaml section. If
|
||||
* this is not set, the variable name will be used
|
||||
*
|
||||
* @return Identifier used for this option or an empty string if the variable
|
||||
* name should be used
|
||||
*/
|
||||
String id() default "";
|
||||
|
||||
/**
|
||||
* Is the parameter required? If set to true, an exception will be thrown if no
|
||||
* default is specified and the option is not specified in the config
|
||||
*
|
||||
* @return Whether this option is required
|
||||
*/
|
||||
boolean isRequired() default true;
|
||||
|
||||
/**
|
||||
* The type of parser used to process the data retrieved from the config.
|
||||
*
|
||||
* @return Returns what processor to use for retrieved config data.
|
||||
*/
|
||||
DataParser processor() default DataParser.DEFAULT;
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.autoload;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.MaterialUtils;
|
||||
|
||||
public enum DataParser {
|
||||
|
||||
DEFAULT,
|
||||
|
||||
MATERIAL {
|
||||
@Override
|
||||
public Object parse(final Object value) {
|
||||
return MaterialUtils.getMaterial(stringify(value));
|
||||
}
|
||||
},
|
||||
|
||||
POTION_EFFECT_TYPE {
|
||||
@Override
|
||||
public Object parse(final Object value) {
|
||||
return PotionEffectType.getByName(stringify(value));
|
||||
}
|
||||
},
|
||||
|
||||
ENTITY_TYPE {
|
||||
@Override
|
||||
public Object parse(final Object value) {
|
||||
try {
|
||||
return EntityType.valueOf(stringify(value));
|
||||
}
|
||||
catch (final Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public Object parse(final Object value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String stringify(final Object value) {
|
||||
return value == null ? "" : value.toString();
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.commands;
|
||||
|
||||
import co.aikar.commands.BukkitCommandCompletionContext;
|
||||
import co.aikar.commands.CommandCompletions;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import vg.civcraft.mc.civmodcore.commands.CommandManager;
|
||||
|
||||
public class CommandRegistrar extends CommandManager {
|
||||
|
||||
public static final String ROOT_ALIAS = "hacks|hack|sah";
|
||||
public static final String PERMISSION_HACKS = "simpleadmin.hacks";
|
||||
|
||||
private final SimpleAdminHacks plugin;
|
||||
|
||||
public CommandRegistrar(final SimpleAdminHacks plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
registerCommand(new HacksCommand(this.plugin));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCompletions(final CommandCompletions<BukkitCommandCompletionContext> completions) {
|
||||
super.registerCompletions(completions);
|
||||
completions.registerAsyncCompletion("hacks", (context) -> {
|
||||
final List<String> names = new ArrayList<>();
|
||||
for (final SimpleHack<? extends SimpleHackConfig> hack : this.plugin.getHackManager().getHacks()) {
|
||||
names.add(hack.getName());
|
||||
}
|
||||
return names;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.commands;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.google.common.base.Strings;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig;
|
||||
import java.util.List;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@CommandPermission(CommandRegistrar.PERMISSION_HACKS)
|
||||
public class HacksCommand extends BaseCommand {
|
||||
|
||||
protected final SimpleAdminHacks plugin;
|
||||
|
||||
public HacksCommand(SimpleAdminHacks plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@CommandAlias(CommandRegistrar.ROOT_ALIAS)
|
||||
@Description("Views the status of a specific hack.")
|
||||
public void viewHacksCommand(final CommandSender sender) {
|
||||
sender.sendMessage("Hacks:");
|
||||
final List<SimpleHack<? extends SimpleHackConfig>> hacks = this.plugin.getHackManager().getHacks();
|
||||
if (hacks.isEmpty()) {
|
||||
sender.sendMessage(" No hacks registered.");
|
||||
}
|
||||
else {
|
||||
for (final SimpleHack<? extends SimpleHackConfig> hack : hacks) {
|
||||
sender.sendMessage(" • " + ChatColor.YELLOW + hack.getName() + ": " + ChatColor.AQUA +
|
||||
(hack.isEnabled() ? "enabled" : "disabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CommandAlias(CommandRegistrar.ROOT_ALIAS)
|
||||
@CommandCompletion("@hacks")
|
||||
@Syntax("<hack>")
|
||||
@Description("Views the status of a specific hack.")
|
||||
public void getStatusCommand(final CommandSender sender, @Single final String hack) {
|
||||
final SimpleHack<? extends SimpleHackConfig> target = this.plugin.getHackManager().getHack(hack);
|
||||
if (target == null) {
|
||||
sender.sendMessage(ChatColor.RED + "That hack could not be found.");
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(ChatColor.WHITE + target.getName() + ":");
|
||||
sender.sendMessage(" " + target.status());
|
||||
}
|
||||
|
||||
@CommandAlias(CommandRegistrar.ROOT_ALIAS)
|
||||
@CommandCompletion("@hacks enable|disable")
|
||||
@Syntax("<hack> <enable/disable>")
|
||||
@Description("Enables or disables a specific hack.")
|
||||
public void setStateCommand(final CommandSender sender, String hack, @Single final String action) {
|
||||
final SimpleHack<? extends SimpleHackConfig> target = this.plugin.getHackManager().getHack(hack);
|
||||
if (target == null) {
|
||||
sender.sendMessage(ChatColor.RED + "That hack could not be found.");
|
||||
return;
|
||||
}
|
||||
hack = target.getClass().getSimpleName();
|
||||
switch (action.toLowerCase()) {
|
||||
case "enable":
|
||||
case "enabled":
|
||||
case "start":
|
||||
case "yes":
|
||||
case "y": {
|
||||
if (target.isEnabled()) {
|
||||
sender.sendMessage(ChatColor.GOLD + hack + " is already enabled.");
|
||||
return;
|
||||
}
|
||||
target.enable();
|
||||
if (!target.isEnabled()) {
|
||||
sender.sendMessage(ChatColor.RED + hack + " could not be enabled!");
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(ChatColor.GREEN + hack + " is now enabled.");
|
||||
return;
|
||||
}
|
||||
case "disable":
|
||||
case "disabled":
|
||||
case "end":
|
||||
case "exit":
|
||||
case "quit":
|
||||
case "kill":
|
||||
case "no":
|
||||
case "n": {
|
||||
if (!target.isEnabled()) {
|
||||
sender.sendMessage(ChatColor.GOLD + hack + " is not enabled.");
|
||||
return;
|
||||
}
|
||||
target.disable();
|
||||
if (target.isEnabled()) {
|
||||
sender.sendMessage(ChatColor.GOLD + hack + " could not be disabled!");
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(ChatColor.GREEN + hack + " has been disabled.");
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
throw new InvalidCommandArgument("Please specify whether to enable to disable the hack.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CommandAlias(CommandRegistrar.ROOT_ALIAS)
|
||||
@CommandCompletion("@hacks get|set @nothing")
|
||||
@Syntax("<hack> <get/set> <key> [value]")
|
||||
@Description("Gets or sets a specific value for a particular hack.")
|
||||
public void getSetValueCommand(final CommandSender sender, final String hack, final String action,
|
||||
final String key, @Optional final String value) {
|
||||
if (Strings.isNullOrEmpty(key)) {
|
||||
throw new InvalidCommandArgument("You need to pass a key.");
|
||||
}
|
||||
final SimpleHack<? extends SimpleHackConfig> target = this.plugin.getHackManager().getHack(hack);
|
||||
if (target == null) {
|
||||
sender.sendMessage(ChatColor.RED + "That hack could not be found.");
|
||||
return;
|
||||
}
|
||||
final SimpleHackConfig config = target.config();
|
||||
switch (action.toLowerCase()) {
|
||||
case "get": {
|
||||
if (!config.has(key)) {
|
||||
sender.sendMessage(target.getName() + ": " + ChatColor.YELLOW + "No value for \"" + key +
|
||||
"\" has been set.");
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(target.getName() + ": " +
|
||||
ChatColor.YELLOW + "\"" + key + "\" == \"" + config.get(key) + "\"");
|
||||
return;
|
||||
}
|
||||
case "set": {
|
||||
try {
|
||||
config.set(key, value);
|
||||
sender.sendMessage(target.getName() + ": " + ChatColor.YELLOW + "\"" + key + "\" = \"" +
|
||||
value + "\"");
|
||||
return;
|
||||
}
|
||||
catch (Exception exception) {
|
||||
sender.sendMessage(target.getName() + ": " + ChatColor.RED + "Failed to set \"" + key +
|
||||
"\" to \"" + value + "\"");
|
||||
return;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
throw new InvalidCommandArgument("Please specify whether to get to set the hack value.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.exceptions;
|
||||
|
||||
public class InvalidConfigException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 7614429135140646756L;
|
||||
|
||||
public InvalidConfigException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidConfigException(final String message, final Throwable source) {
|
||||
super(message, source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.utilities;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import vg.civcraft.mc.civmodcore.world.WorldUtils;
|
||||
|
||||
public final class BetterToString {
|
||||
|
||||
public static String location(final Location location) {
|
||||
if (location == null) {
|
||||
return "<null>";
|
||||
}
|
||||
final World world = WorldUtils.getLocationWorld(location);
|
||||
return (world == null ? "<null world>" : world.getName())
|
||||
+ ":"
|
||||
+ "x=" + location.getX()
|
||||
+ "y=" + location.getY()
|
||||
+ "z=" + location.getZ()
|
||||
+ ";"
|
||||
+ "pitch=" + location.getPitch()
|
||||
+ "yaw=" + location.getYaw();
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.utilities;
|
||||
|
||||
/**
|
||||
* Various Broadcast targets
|
||||
@@ -9,5 +9,5 @@ public enum BroadcastLevel {
|
||||
OP,
|
||||
PERM,
|
||||
CONSOLE,
|
||||
ALL;
|
||||
ALL
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.utilities;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class PacketManager {
|
||||
|
||||
private final ProtocolManager manager;
|
||||
private final List<PacketAdapter> adapters;
|
||||
|
||||
public PacketManager() {
|
||||
this.manager = ProtocolLibrary.getProtocolManager();
|
||||
this.adapters = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addAdapter(final PacketAdapter adapter) {
|
||||
Preconditions.checkNotNull(adapter, "Adapter cannot be null!");
|
||||
this.manager.addPacketListener(adapter);
|
||||
this.adapters.add(adapter);
|
||||
}
|
||||
|
||||
public void removeAllAdapters() {
|
||||
this.adapters.forEach(this.manager::removePacketListener);
|
||||
this.adapters.clear();
|
||||
}
|
||||
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.framework.utilities;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import java.util.LinkedList;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class TeleportUtil {
|
||||
|
||||
private TeleportUtil() {
|
||||
//static only, no constructor
|
||||
}
|
||||
|
||||
public static boolean checkForTeleportSpace(Location loc) {
|
||||
final Block block = loc.getBlock();
|
||||
final Material mat = block.getType();
|
||||
if (mat.isSolid()) {
|
||||
return false;
|
||||
}
|
||||
final Block above = block.getRelative(BlockFace.UP);
|
||||
if (above.getType().isSolid()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean tryToTeleportVertically(Player player, Location location, String reason) {
|
||||
Location loc = location.clone();
|
||||
loc.setX(Math.floor(loc.getX()) + 0.500000D);
|
||||
loc.setY(Math.floor(loc.getY()) + 0.02D);
|
||||
loc.setZ(Math.floor(loc.getZ()) + 0.500000D);
|
||||
final Location baseLoc = loc.clone();
|
||||
final World world = baseLoc.getWorld();
|
||||
// Check if teleportation here is viable
|
||||
boolean performTeleport = checkForTeleportSpace(loc);
|
||||
if (!performTeleport) {
|
||||
loc.setY(loc.getY() + 1.000000D);
|
||||
performTeleport = checkForTeleportSpace(loc);
|
||||
}
|
||||
if (performTeleport) {
|
||||
player.setVelocity(new Vector());
|
||||
player.teleport(loc);
|
||||
SimpleAdminHacks.instance().log(String.format(
|
||||
"Player '%s' %s: Teleported to %s",
|
||||
player.getName(), reason, loc.toString()));
|
||||
return true;
|
||||
}
|
||||
loc = baseLoc.clone();
|
||||
// Create a sliding window of block types and track how many of those
|
||||
// are solid. Keep fetching the block below the current block to move down.
|
||||
int air_count = 0;
|
||||
LinkedList<Material> air_window = new LinkedList<>();
|
||||
loc.setY((float)world.getMaxHeight() - 2);
|
||||
Block block = world.getBlockAt(loc);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
Material block_mat = block.getType();
|
||||
if (!block_mat.isSolid()) {
|
||||
++air_count;
|
||||
}
|
||||
air_window.addLast(block_mat);
|
||||
block = block.getRelative(BlockFace.DOWN);
|
||||
}
|
||||
// Now that the window is prepared, scan down the Y-axis.
|
||||
while (block.getY() >= block.getWorld().getMinHeight() + 1) {
|
||||
Material blockMat = block.getType();
|
||||
if (blockMat.isSolid()) {
|
||||
if (air_count == 4) {
|
||||
player.setVelocity(new Vector());
|
||||
loc = block.getLocation();
|
||||
loc.setX(Math.floor(loc.getX()) + 0.500000D);
|
||||
loc.setY(loc.getY() + 1.02D);
|
||||
loc.setZ(Math.floor(loc.getZ()) + 0.500000D);
|
||||
player.teleport(loc);
|
||||
SimpleAdminHacks.instance().log(String.format(
|
||||
"Player '%s' %s: Teleported to %s",
|
||||
player.getName(), reason, loc.toString()));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
++air_count;
|
||||
}
|
||||
air_window.addLast(blockMat);
|
||||
if (!air_window.removeFirst().isSolid()) {
|
||||
--air_count;
|
||||
}
|
||||
block = block.getRelative(BlockFace.DOWN);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.BadBoyWatchConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
|
||||
/**
|
||||
* Watches for bad boys by tracking block breaks.
|
||||
* FIRST HIT will also catch breaks that block protection plugins cancel, which if you skip
|
||||
* can lead to confusion
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*
|
||||
*/
|
||||
public class BadBoyWatch extends SimpleHack<BadBoyWatchConfig> implements Listener {
|
||||
|
||||
/**
|
||||
* tracking cache, persists and ignores logouts.
|
||||
*/
|
||||
private Map<UUID, BadBoyRecord> boys = null;
|
||||
private Map<UUID, BadBoyRecord> lowBoys = null;
|
||||
|
||||
public BadBoyWatch(SimpleAdminHacks plugin, BadBoyWatchConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true)
|
||||
public void breakListenLow(BlockBreakEvent bbe) {
|
||||
if (!config.isEnabled()) return;
|
||||
try {
|
||||
Player player = bbe.getPlayer();
|
||||
Block block = bbe.getBlock();
|
||||
BlockState bs = block.getState();
|
||||
Material material = bs.getType();
|
||||
|
||||
lowTrackAndReport(player.getUniqueId(), block.getLocation(), material);
|
||||
} catch (Exception e) {
|
||||
// insane catchall
|
||||
plugin().log(Level.WARNING, "Failed to track a low break for badboy", e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled=true)
|
||||
public void breakListen(BlockBreakEvent bbe) {
|
||||
if (!config.isEnabled()) return;
|
||||
try {
|
||||
Player player = bbe.getPlayer();
|
||||
Block block = bbe.getBlock();
|
||||
BlockState bs = block.getState();
|
||||
Material material = bs.getType();
|
||||
|
||||
trackAndReport(player.getUniqueId(), block.getLocation(), material);
|
||||
} catch (Exception e) {
|
||||
// insane catchall
|
||||
plugin().log(Level.WARNING, "Failed to track a break for badboy", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void trackAndReport(UUID uuid, Location location, Material material) {
|
||||
if (uuid == null || location == null || material == null) return;
|
||||
|
||||
BadBoyRecord record = boys.get(uuid);
|
||||
if (record == null) {
|
||||
record = new BadBoyRecord(config);
|
||||
boys.put(uuid, record);
|
||||
}
|
||||
|
||||
String report = record.registerBreak(location, material);
|
||||
if (report != null) {
|
||||
plugin().log(uuid.toString() + "} " + report);
|
||||
}
|
||||
}
|
||||
|
||||
private void lowTrackAndReport(UUID uuid, Location location, Material material) {
|
||||
if (uuid == null || location == null || material == null) return;
|
||||
|
||||
BadBoyRecord record = lowBoys.get(uuid);
|
||||
if (record == null) {
|
||||
record = new BadBoyRecord(config);
|
||||
lowBoys.put(uuid, record);
|
||||
}
|
||||
|
||||
String report = record.registerBreak(location, material);
|
||||
if (report != null) {
|
||||
plugin().log(uuid.toString() + "} FIRST HITS " + report);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering BadBoyWatcher listener");
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
boys = new ConcurrentHashMap<>();
|
||||
lowBoys = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
boys.clear();
|
||||
lowBoys.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
if (!config.isEnabled()) {
|
||||
return "Bad Boy Listening disabled.";
|
||||
}
|
||||
StringBuffer status = new StringBuffer("Listening for bad boy breaks");
|
||||
|
||||
status.append("\n Currently watching ").append(boys.size()).append(" players.");
|
||||
status.append("\n Currently watching LOW ").append(lowBoys.size()).append(" players.");
|
||||
return status.toString();
|
||||
}
|
||||
|
||||
public static BadBoyWatchConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new BadBoyWatchConfig(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {}
|
||||
|
||||
private static class BadBoyRecord {
|
||||
private int nextBreak;
|
||||
private int breakCount;
|
||||
private BadBoyBlock[] breaks;
|
||||
private BadBoyWatchConfig config;
|
||||
|
||||
public BadBoyRecord(BadBoyWatchConfig config) {
|
||||
this.config = config;
|
||||
this.nextBreak = 0;
|
||||
this.breakCount = 0;
|
||||
this.breaks = new BadBoyBlock[config.getTrackingDepth() + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string if this is a watched break that passes all checks.
|
||||
* Handles abiding the config too.
|
||||
* @return null if not watched break or if conditions not met, string of
|
||||
* breaks leading to this otherwise.
|
||||
*/
|
||||
public synchronized String registerBreak(Location location, Material material) {
|
||||
breaks[nextBreak] = new BadBoyBlock(location, material);
|
||||
|
||||
nextBreak = (nextBreak + 1) % breaks.length;
|
||||
breakCount ++;
|
||||
|
||||
if (config.getWatchedMaterials().contains(material)) {
|
||||
String breaks = null;
|
||||
if (breakCount >= config.getMinDepthToMatch()) {
|
||||
breaks = showBreaks();
|
||||
}
|
||||
if (config.isClearOnMatch()) {
|
||||
this.clear();
|
||||
breakCount = 0;
|
||||
}
|
||||
return breaks;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears everything tracked and resets break pointer.
|
||||
*/
|
||||
private void clear() {
|
||||
for (int i = 0; i < breaks.length; i++) {
|
||||
breaks[i] = null;
|
||||
}
|
||||
nextBreak = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just outputs what we know right now.
|
||||
* @return a String showing locations and block materials
|
||||
*/
|
||||
private String showBreaks() {
|
||||
StringBuilder sb = new StringBuilder("BadBoyBreak: ");
|
||||
int max = breaks.length;
|
||||
|
||||
for (int i = (nextBreak - 1 + max) % max; i != nextBreak; i = (i - 1 + max) % max) {
|
||||
BadBoyBlock bbb = breaks[i];
|
||||
if (bbb == null) break;
|
||||
sb.append('[').append(bbb.toString()).append(']');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class BadBoyBlock {
|
||||
public final Location location;
|
||||
public final Material material;
|
||||
|
||||
public BadBoyBlock(Location location, Material material) {
|
||||
this.location = location;
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder se = new StringBuilder();
|
||||
|
||||
se.append(location.getWorld().getName());
|
||||
se.append('(').append(location.getBlockX()).append(',')
|
||||
.append(location.getBlockY()).append(',')
|
||||
.append(location.getBlockZ()).append(')');
|
||||
se.append(material.toString());
|
||||
return se.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
-18
@@ -1,32 +1,30 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.CTAnnounceConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.BroadcastLevel;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minelink.ctplus.event.PlayerCombatTagEvent;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.minelink.ctplus.event.PlayerCombatTagEvent;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.BroadcastLevel;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.CTAnnounceConfig;
|
||||
|
||||
/**
|
||||
* Ties into CombatTagPlus, listens for {@link PlayerCombatTagEvent}
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class CTAnnounce extends SimpleHack<CTAnnounceConfig> implements Listener{
|
||||
|
||||
|
||||
public static final String NAME = "CombatTagAnnounce";
|
||||
|
||||
|
||||
private Map<UUID, Long> lastCTAnnounce;
|
||||
|
||||
|
||||
public CTAnnounce(SimpleAdminHacks plugin, CTAnnounceConfig config) {
|
||||
super(plugin, config);
|
||||
|
||||
@@ -35,18 +33,18 @@ public class CTAnnounce extends SimpleHack<CTAnnounceConfig> implements Listener
|
||||
config.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Capture player combattag and broadcast it
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void CTEvent(PlayerCombatTagEvent event) {
|
||||
public void ctEvent(PlayerCombatTagEvent event) {
|
||||
if (!config.isEnabled()) return; // ignore if off
|
||||
if (event.getVictim() == null || event.getAttacker() == null) return; // ignore non-pvp and admin-pvp
|
||||
plugin().debug(" Victim: {0} Attacker: {1}", event.getVictim().getName(), event.getAttacker().getName());
|
||||
|
||||
|
||||
// Throttle broadcast frequency
|
||||
Long lastTag = lastCTAnnounce.get(event.getVictim().getUniqueId());
|
||||
Long now = System.currentTimeMillis();
|
||||
@@ -55,7 +53,7 @@ public class CTAnnounce extends SimpleHack<CTAnnounceConfig> implements Listener
|
||||
|
||||
// Prepare message
|
||||
String cleanMessage = cleanMessage(event);
|
||||
|
||||
|
||||
// Overlap is possible. Some people might get double-notified
|
||||
for (BroadcastLevel level : config.getBroadcast()) {
|
||||
plugin().debug(" Broadcast to {0}", level);
|
||||
@@ -75,7 +73,7 @@ public class CTAnnounce extends SimpleHack<CTAnnounceConfig> implements Listener
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String cleanMessage(PlayerCombatTagEvent event) {
|
||||
return ChatColor.translateAlternateColorCodes('&',
|
||||
config.getBroadcastMessage()
|
||||
@@ -98,7 +96,7 @@ public class CTAnnounce extends SimpleHack<CTAnnounceConfig> implements Listener
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
lastCTAnnounce = new ConcurrentHashMap<UUID, Long>();
|
||||
lastCTAnnounce = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,4 +121,8 @@ public class CTAnnounce extends SimpleHack<CTAnnounceConfig> implements Listener
|
||||
return "CombatTagPlus.PlayerCombatTagEvent monitoring not active";
|
||||
}
|
||||
}
|
||||
|
||||
public static CTAnnounceConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new CTAnnounceConfig(plugin, config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.DisableAIConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataContainer;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public final class DisableAI extends SimpleHack<DisableAIConfig> implements Listener {
|
||||
|
||||
private static final String HAS_BEEN_DISABLED_KEY = "SAH_AI_DISABLED";
|
||||
|
||||
public DisableAI(final SimpleAdminHacks plugin, final DisableAIConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
public static DisableAIConfig generate(final SimpleAdminHacks plugin, final ConfigurationSection config) {
|
||||
return new DisableAIConfig(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
HandlerList.unregisterAll(this);
|
||||
config().reset();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void disableModAI(final EntityAddToWorldEvent event) {
|
||||
final var entity = event.getEntity();
|
||||
if (!(entity instanceof LivingEntity)) {
|
||||
return;
|
||||
}
|
||||
final var livingEntity = (LivingEntity) entity;
|
||||
final var nbt = new CompoundTag(((CraftPersistentDataContainer) entity.getPersistentDataContainer()).getRaw()){};
|
||||
if (!config().isLimitingEntityAI(entity.getType(), entity.getEntitySpawnReason())) {
|
||||
// If the entity was disabled before, re-enable it
|
||||
if (nbt.contains(HAS_BEEN_DISABLED_KEY)) {
|
||||
livingEntity.setAI(nbt.getBoolean(HAS_BEEN_DISABLED_KEY));
|
||||
nbt.remove(HAS_BEEN_DISABLED_KEY);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// If the entity has already been disabled, leave alone
|
||||
if (nbt.contains(HAS_BEEN_DISABLED_KEY)) {
|
||||
return;
|
||||
}
|
||||
nbt.putBoolean(HAS_BEEN_DISABLED_KEY, livingEntity.hasAI());
|
||||
livingEntity.setAI(false);
|
||||
}
|
||||
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerElytraBoostEvent;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.ElytraFeaturesConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import java.util.Comparator;
|
||||
import javax.annotation.Nonnull;
|
||||
import net.minelink.ctplus.CombatTagPlus;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityToggleGlideEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
public final class ElytraFeatures extends SimpleHack<ElytraFeaturesConfig> implements Listener {
|
||||
|
||||
public ElytraFeatures(@Nonnull final SimpleAdminHacks plugin,
|
||||
@Nonnull final ElytraFeaturesConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
public static ElytraFeaturesConfig generate(@Nonnull final SimpleAdminHacks plugin,
|
||||
@Nonnull final ConfigurationSection config) {
|
||||
return new ElytraFeaturesConfig(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
private boolean INTERNAL_hasBypassPermission(final Entity entity) {
|
||||
return entity instanceof Player && entity.hasPermission("simpleadmin.elytrabypass");
|
||||
}
|
||||
|
||||
private boolean INTERNAL_isInCombat(final Entity entity) {
|
||||
if (!(entity instanceof Player)) {
|
||||
return false;
|
||||
}
|
||||
final PluginManager pluginManager = Bukkit.getPluginManager();
|
||||
final Plugin foundPlugin = pluginManager.getPlugin("CombatTagPlus");
|
||||
if (pluginManager.isPluginEnabled(foundPlugin)) {
|
||||
final CombatTagPlus combatTagPlugin = (CombatTagPlus) foundPlugin;
|
||||
return combatTagPlugin.getTagManager().isTagged(entity.getUniqueId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Elytra flight
|
||||
// ------------------------------------------------------------
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void regulateElytraFlight(@Nonnull final EntityToggleGlideEvent event) {
|
||||
boolean disableFlight = false;
|
||||
if (config().isFlightDisabled()) {
|
||||
disableFlight = true;
|
||||
}
|
||||
else {
|
||||
if (config().isFlightDisabledInCombat()) {
|
||||
disableFlight = INTERNAL_isInCombat(event.getEntity());
|
||||
}
|
||||
}
|
||||
if (disableFlight) {
|
||||
if (!INTERNAL_hasBypassPermission(event.getEntity())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Elytra boosting
|
||||
// ------------------------------------------------------------
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void regulateElytraBoosting(@Nonnull final PlayerElytraBoostEvent event) {
|
||||
boolean disableBoosting = false;
|
||||
if (config().isBoostingDisabled()) {
|
||||
disableBoosting = true;
|
||||
}
|
||||
else {
|
||||
if (config().isBoostingDisabledInCombat()) {
|
||||
if (INTERNAL_isInCombat(event.getPlayer())) {
|
||||
disableBoosting = true;
|
||||
}
|
||||
}
|
||||
if (config().isSafeBoostingDisabled()) {
|
||||
if (!event.getFirework().getFireworkMeta().hasEffects()) {
|
||||
disableBoosting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (disableBoosting) {
|
||||
if (!INTERNAL_hasBypassPermission(event.getPlayer())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Elytra damage
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private static final class ElytraDamage {
|
||||
private long lastDamageTime;
|
||||
private double damageToDeal;
|
||||
}
|
||||
|
||||
private final Object2ObjectMap<Player, ElytraDamage> damageElytraFlightTracker =
|
||||
new Object2ObjectAVLTreeMap<>(Comparator.comparing(Player::getUniqueId));
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void damageFliersAboveWorldHeight(final PlayerMoveEvent event) {
|
||||
if (config().getHeightDamage() <= 0) {
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
if (!player.isGliding() || INTERNAL_hasBypassPermission(player)) {
|
||||
return;
|
||||
}
|
||||
final Location fromLocation = event.getFrom();
|
||||
final int allowedHeight = fromLocation.getWorld().getMaxHeight() + config().getHeightBuffer();
|
||||
final int blocksAboveAllowedHeight = fromLocation.getBlockY() - allowedHeight;
|
||||
// If the player is within the allowed height, do nothing
|
||||
if (blocksAboveAllowedHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
final ElytraDamage details = this.damageElytraFlightTracker.computeIfAbsent(
|
||||
player, (_key) -> new ElytraDamage());
|
||||
details.damageToDeal = Math.max(details.damageToDeal,
|
||||
config().getHeightDamage() * blocksAboveAllowedHeight * config().isHeightDamageScaling());
|
||||
final long now = System.currentTimeMillis();
|
||||
final long deltaInterval = now - details.lastDamageTime;
|
||||
// If it's not the right time to damage the player, do nothing
|
||||
if (deltaInterval < config().getHeightDamageInterval()) {
|
||||
return;
|
||||
}
|
||||
player.damage(details.damageToDeal);
|
||||
details.damageToDeal = 0;
|
||||
details.lastDamageTime = now;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void resetDamageElytraFlightOnLogout(final PlayerQuitEvent event) {
|
||||
this.damageElytraFlightTracker.remove(event.getPlayer());
|
||||
}
|
||||
|
||||
}
|
||||
+244
-225
@@ -1,225 +1,244 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.bukkit.event.player.PlayerPortalEvent;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.ExperimentalConfig;
|
||||
|
||||
public class Experimental extends SimpleHack<ExperimentalConfig> implements Listener, CommandExecutor {
|
||||
|
||||
public static final String NAME = "Experimental";
|
||||
|
||||
public Experimental(SimpleAdminHacks plugin, ExperimentalConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering experimental listeners");
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering experimental commands");
|
||||
plugin().registerCommand("serialize", this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
if (config.isEnabled()) {
|
||||
StringBuilder sb = new StringBuilder("Experiments enabled:");
|
||||
if (config.isCombatSpy()) {
|
||||
sb.append("\n CombatSpy is on");
|
||||
} else {
|
||||
sb.append("\n CombatSpy is off");
|
||||
}
|
||||
if (config.isTeleportSpy()) {
|
||||
sb.append("\n TeleportSpy is on");
|
||||
} else {
|
||||
sb.append("\n TeleportSpy is off");
|
||||
}
|
||||
return sb.toString();
|
||||
} else {
|
||||
return "Experiments disabled.";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage("Must be a player to execute this command");
|
||||
return true;
|
||||
}
|
||||
|
||||
Player player = (Player) sender;
|
||||
ItemStack item = player.getInventory().getItemInMainHand();
|
||||
if (item != null) {
|
||||
YamlConfiguration yml = new YamlConfiguration();
|
||||
yml.set("template", item);
|
||||
plugin().log(yml.saveToString());
|
||||
sender.sendMessage(yml.saveToString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
|
||||
private void monitorTeleportLow(PlayerTeleportEvent event) {
|
||||
if (!config.isTeleportSpy()) return;
|
||||
StringBuffer sb = new StringBuffer("[LO] ");
|
||||
logTeleport(event, sb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false)
|
||||
private void monitorTeleportHigh(PlayerTeleportEvent event) {
|
||||
if (!config.isTeleportSpy()) return;
|
||||
StringBuffer sb = new StringBuffer("[HI] ");
|
||||
logTeleport(event, sb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
private void monitorTeleportTrack(PlayerPortalEvent event) {
|
||||
if (!config.isPostTeleportSpy()) return;
|
||||
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
new BukkitRunnable() {
|
||||
final UUID playerUUID = player.getUniqueId();
|
||||
private int runCount = 0;
|
||||
public void run() {
|
||||
runCount++;
|
||||
if (runCount > config.getPostTeleportSpyCount()) {
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
if (playerUUID != null) {
|
||||
Player player = plugin().getServer().getPlayer(playerUUID);
|
||||
if (player != null) {
|
||||
StringBuffer sb = new StringBuffer("Tracking: ");
|
||||
sb.append(playerUUID);
|
||||
logPlayer(player, sb);
|
||||
plugin().log(sb.toString());
|
||||
} else {
|
||||
StringBuffer sb = new StringBuffer("Lost: ");
|
||||
sb.append(playerUUID);
|
||||
plugin().log(sb.toString());
|
||||
this.cancel();
|
||||
}
|
||||
} else {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(plugin(), 2l, 4l);
|
||||
}
|
||||
|
||||
private void logTeleport(PlayerTeleportEvent event, StringBuffer sb) {
|
||||
sb.append(event.isCancelled() ? "C " : "A ");
|
||||
sb.append(event.getCause().name());
|
||||
Player player = event.getPlayer();
|
||||
Location from = event.getFrom();
|
||||
Location to = event.getTo();
|
||||
sb.append(String.format(" %16s", player != null ? player.getName() : "--unknown--"));
|
||||
if (from != null) {
|
||||
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", from.getWorld().getName(), from.getX(), from.getY(), from.getZ()));
|
||||
} else {
|
||||
sb.append(" (none)");
|
||||
}
|
||||
sb.append(" ->");
|
||||
if (to != null) {
|
||||
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", to.getWorld().getName(), to.getX(), to.getY(), to.getZ()));
|
||||
} else {
|
||||
sb.append(" (none)");
|
||||
}
|
||||
sb.append(" [").append(player.getUniqueId()).append(" ");
|
||||
logPlayer(player, sb);
|
||||
sb.append("]");
|
||||
plugin().log(sb.toString());
|
||||
}
|
||||
|
||||
private void logPlayer(final Player player, StringBuffer sb) {
|
||||
sb.append(player.getWorld().getName());
|
||||
Location feet = player.getLocation();
|
||||
Location eyes = player.getEyeLocation();
|
||||
if (feet != null) {
|
||||
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", feet.getWorld().getName(), feet.getX(), feet.getY(), feet.getZ()));
|
||||
} else {
|
||||
sb.append(" (none)");
|
||||
}
|
||||
if (eyes != null) {
|
||||
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", eyes.getWorld().getName(), eyes.getX(), eyes.getY(), eyes.getZ()));
|
||||
} else {
|
||||
sb.append(" (none)");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
|
||||
private void monitorCombatLow(EntityDamageByEntityEvent event) {
|
||||
if (!config.isCombatSpy()) return;
|
||||
StringBuffer sb = new StringBuffer("[LO] ");
|
||||
logCombat(event, sb);
|
||||
}
|
||||
|
||||
private void logCombat(EntityDamageByEntityEvent event, StringBuffer sb) {
|
||||
sb.append(event.isCancelled() ? "C " : "A ");
|
||||
sb.append(event.getCause().name());
|
||||
sb.append(String.format(", %5.2f->%5.2f", event.getDamage(), event.getFinalDamage()));
|
||||
sb.append(String.format(", %16s v %16s",
|
||||
event.getDamager() != null ? event.getDamager().getName() : "--unknown--",
|
||||
event.getEntity() != null ? event.getEntity().getName() : "--unknown--" ));
|
||||
for (EntityDamageEvent.DamageModifier mod : EntityDamageEvent.DamageModifier.values()) {
|
||||
sb.append(", ").append(mod.name());
|
||||
try {
|
||||
sb.append(String.format(" %5.2f->%5.2f", event.getOriginalDamage(mod), event.getDamage(mod)));
|
||||
} catch (Exception e) {
|
||||
sb.append(" --e--/--e--");
|
||||
}
|
||||
}
|
||||
plugin().log(sb.toString());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
|
||||
private void monitorCombatHigh(EntityDamageByEntityEvent event) {
|
||||
if (!config.isCombatSpy()) return;
|
||||
StringBuffer sb = new StringBuffer("[HI]: ");
|
||||
logCombat(event, sb);
|
||||
}
|
||||
}
|
||||
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.ExperimentalConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.player.PlayerPortalEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
public class Experimental extends SimpleHack<ExperimentalConfig> implements Listener, CommandExecutor {
|
||||
|
||||
public static final String NAME = "Experimental";
|
||||
|
||||
public Experimental(SimpleAdminHacks plugin, ExperimentalConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering experimental listeners");
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering experimental commands");
|
||||
plugin().registerCommand("serialize", this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
if (config.isEnabled()) {
|
||||
StringBuilder sb = new StringBuilder("Experiments enabled:");
|
||||
if (config.isCombatSpy()) {
|
||||
sb.append("\n CombatSpy is on");
|
||||
} else {
|
||||
sb.append("\n CombatSpy is off");
|
||||
}
|
||||
if (config.isTeleportSpy()) {
|
||||
sb.append("\n TeleportSpy is on");
|
||||
} else {
|
||||
sb.append("\n TeleportSpy is off");
|
||||
}
|
||||
return sb.toString();
|
||||
} else {
|
||||
return "Experiments disabled.";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage("Must be a player to execute this command");
|
||||
return true;
|
||||
}
|
||||
|
||||
Player player = (Player) sender;
|
||||
ItemStack item = player.getInventory().getItemInMainHand();
|
||||
if (item != null && item.getType().isItem()) { // spigot claims @Notnull but unclear how well enforced
|
||||
YamlConfiguration yml = new YamlConfiguration();
|
||||
yml.set("template", item);
|
||||
plugin().log(yml.saveToString());
|
||||
sender.sendMessage(yml.saveToString());
|
||||
} else {
|
||||
sender.sendMessage("No valid item in main hand");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
|
||||
private void monitorTeleportLow(PlayerTeleportEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isTeleportSpy()) return;
|
||||
StringBuilder sb = new StringBuilder("[LO] ");
|
||||
logTeleport(event, sb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false)
|
||||
private void monitorTeleportHigh(PlayerTeleportEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isTeleportSpy()) return;
|
||||
StringBuilder sb = new StringBuilder("[HI] ");
|
||||
logTeleport(event, sb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
private void monitorTeleportTrack(PlayerPortalEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isPostTeleportSpy()) return;
|
||||
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
new BukkitRunnable() {
|
||||
final UUID playerUUID = player.getUniqueId();
|
||||
private int runCount = 0;
|
||||
public void run() {
|
||||
runCount++;
|
||||
if (runCount > config.getPostTeleportSpyCount()) {
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
// I recall running into situation where this UUID nulled out, don't remember how
|
||||
// so, I check.
|
||||
if (playerUUID != null) {
|
||||
Player player = plugin().getServer().getPlayer(playerUUID);
|
||||
if (player != null) {
|
||||
StringBuilder sb = new StringBuilder("Tracking: ");
|
||||
sb.append(playerUUID);
|
||||
logPlayer(player, sb);
|
||||
plugin().log(sb.toString());
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder("Lost: ");
|
||||
sb.append(playerUUID);
|
||||
plugin().log(sb.toString());
|
||||
this.cancel();
|
||||
}
|
||||
} else {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(plugin(), 2l, 4l);
|
||||
}
|
||||
|
||||
private void logTeleport(PlayerTeleportEvent event, StringBuilder sb) {
|
||||
sb.append(event.isCancelled() ? "C " : "A ");
|
||||
sb.append(event.getCause().name());
|
||||
Player player = event.getPlayer();
|
||||
Location from = event.getFrom();
|
||||
Location to = event.getTo();
|
||||
// Most of these nullchecks will gen warnings with compile time contracts.
|
||||
// Experience tells me these can be violated at runtime due to spigot failures,
|
||||
// esp moving between worlds with corresponding state desync. Leaving them in
|
||||
// consequentially.
|
||||
sb.append(String.format(" %16s", player != null ? player.getName() : "--unknown--"));
|
||||
if (from != null) {
|
||||
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", from.getWorld().getName(), from.getX(), from.getY(), from.getZ()));
|
||||
} else {
|
||||
sb.append(" (none)");
|
||||
}
|
||||
sb.append(" ->");
|
||||
if (to != null) {
|
||||
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", to.getWorld().getName(), to.getX(), to.getY(), to.getZ()));
|
||||
} else {
|
||||
sb.append(" (none)");
|
||||
}
|
||||
sb.append(" [").append(player.getUniqueId()).append(" ");
|
||||
logPlayer(player, sb);
|
||||
sb.append("]");
|
||||
plugin().log(sb.toString());
|
||||
}
|
||||
|
||||
private void logPlayer(final Player player, StringBuilder sb) {
|
||||
sb.append(player.getWorld().getName());
|
||||
Location feet = player.getLocation();
|
||||
Location eyes = player.getEyeLocation();
|
||||
// Similar comment here, most/all these nullchecks are from observed failures.
|
||||
// I truly hope Spigot has eliminated all sources of these but I'm not the trusting type.
|
||||
if (feet != null) {
|
||||
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", feet.getWorld().getName(), feet.getX(), feet.getY(), feet.getZ()));
|
||||
} else {
|
||||
sb.append(" (none)");
|
||||
}
|
||||
if (eyes != null) {
|
||||
sb.append(String.format(" %s,%5.0f,%3.0f,%5.0f", eyes.getWorld().getName(), eyes.getX(), eyes.getY(), eyes.getZ()));
|
||||
} else {
|
||||
sb.append(" (none)");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
|
||||
private void monitorCombatLow(EntityDamageByEntityEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isCombatSpy()) return;
|
||||
StringBuilder sb = new StringBuilder("[LO] ");
|
||||
logCombat(event, sb);
|
||||
}
|
||||
|
||||
private void logCombat(EntityDamageByEntityEvent event, StringBuilder sb) {
|
||||
sb.append(event.isCancelled() ? "C " : "A ");
|
||||
sb.append(event.getCause().name());
|
||||
// These null checks defend against specific kinds of malformed damage events, which can occur
|
||||
// at runtime or while running with older plugins.
|
||||
sb.append(String.format(", %5.2f->%5.2f", event.getDamage(), event.getFinalDamage()));
|
||||
sb.append(String.format(", %16s v %16s",
|
||||
event.getDamager() != null ? event.getDamager().getName() : "--unknown--",
|
||||
event.getEntity() != null ? event.getEntity().getName() : "--unknown--"));
|
||||
for (EntityDamageEvent.DamageModifier mod : EntityDamageEvent.DamageModifier.values()) {
|
||||
sb.append(", ").append(mod.name());
|
||||
try {
|
||||
sb.append(String.format(" %5.2f->%5.2f", event.getOriginalDamage(mod), event.getDamage(mod)));
|
||||
} catch (Exception e) {
|
||||
sb.append(" --e--/--e--");
|
||||
}
|
||||
}
|
||||
plugin().log(sb.toString());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
|
||||
private void monitorCombatHigh(EntityDamageByEntityEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isCombatSpy()) return;
|
||||
StringBuilder sb = new StringBuilder("[HI]: ");
|
||||
logCombat(event, sb);
|
||||
}
|
||||
|
||||
public static ExperimentalConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new ExperimentalConfig(plugin, config);
|
||||
}
|
||||
}
|
||||
|
||||
+580
@@ -0,0 +1,580 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.GameFeaturesConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.TeleportUtil;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.type.Dispenser;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockDispenseEvent;
|
||||
import org.bukkit.event.block.BlockFromToEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityResurrectEvent;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.inventory.FurnaceExtractEvent;
|
||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.inventory.PrepareSmithingEvent;
|
||||
import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.vehicle.VehicleDestroyEvent;
|
||||
import org.bukkit.event.vehicle.VehicleExitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.SmithingInventory;
|
||||
import vg.civcraft.mc.civmodcore.inventory.InventoryUtils;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;
|
||||
|
||||
/**
|
||||
* This is a grab-bag class to hold any _features_ related configurations that impact the
|
||||
* game, server-wide. Mostly focused on turning things on or off.
|
||||
*
|
||||
* It's part of a series of focused hacks.
|
||||
*
|
||||
* {@link GameFixes} is focused on things that are broken or don't work, and attempts to fix them.
|
||||
* {@link GameFeatures} focuses on enabling and disabling features, like ender chests, various potion states.
|
||||
* {@link GameTuning} neither fixes nor disables, but rather adjusts and reconfigures.
|
||||
*
|
||||
* Currently you can control the following:
|
||||
* - Disable Potato XP
|
||||
*/
|
||||
public class GameFeatures extends SimpleHack<GameFeaturesConfig> implements Listener {
|
||||
public static final String NAME = "GameFeatures";
|
||||
|
||||
public GameFeatures(SimpleAdminHacks plugin, GameFeaturesConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config != null && config.isEnabled()) {
|
||||
plugin().log("Registering GameFeatures listeners");
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
// Bukkit does this for us.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
StringBuilder genStatus = new StringBuilder();
|
||||
genStatus.append("GameFeatures is ");
|
||||
if (config != null && config.isEnabled()) {
|
||||
genStatus.append("active\n");
|
||||
if (config.isPotatoXPEnabled()) {
|
||||
genStatus.append(" Potato XP is enabled\n");
|
||||
} else {
|
||||
genStatus.append(" Potato XP is disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Villager Trading is ");
|
||||
if (config.isVillagerTrading()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Wither Spawning is ");
|
||||
if (config.isWitherSpawning()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Patrol Spawning is ");
|
||||
if (config.isPatrolSpawning()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Phantom Spawning is ");
|
||||
if (config.isPhantomSpawning()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Ender Chest placement is ");
|
||||
if (config.isEnderChestPlacement()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Ender Chest use is ");
|
||||
if (config.isEnderChestUse()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Shulker Box use is ");
|
||||
if (config.isShulkerBoxUse()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Totem of Undying effects are ");
|
||||
if (config.isTotemPowers()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Chorus Fruit teleportation is ");
|
||||
if (config.isChorusFruitTeleportation()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" WeepAngel is ");
|
||||
if (config.isWeepingAngel()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Block water in HELL biomes is ");
|
||||
if (config.isBlockWaterInHell()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Minecart teleporter is ");
|
||||
if (config.isMinecartTeleport()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Obsidian generator 1.7 is ");
|
||||
if (config.isObsidianGenerators()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Personal death messages is ");
|
||||
if (config.isPersonalDeathMessages()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Netherite crafting in smithing table is ");
|
||||
if (!config.isDisableNetheriteCrafting()) {
|
||||
genStatus.append("disabled\n");
|
||||
} else {
|
||||
genStatus.append("enabled\n");
|
||||
}
|
||||
// more?
|
||||
} else {
|
||||
genStatus.append("inactive");
|
||||
}
|
||||
return genStatus.toString();
|
||||
}
|
||||
|
||||
public static GameFeaturesConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new GameFeaturesConfig(plugin, config);
|
||||
}
|
||||
|
||||
/* From here on, the actual meat of the hack. Above is basically boilerplate for micro-plugins.*/
|
||||
|
||||
/**
|
||||
* Perhaps eventually generalize?
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void potatoXP(FurnaceExtractEvent event) {
|
||||
if (!config.isEnabled() || config.isPotatoXPEnabled()) return;
|
||||
try {
|
||||
Material mat = event.getItemType();
|
||||
|
||||
if (Material.BAKED_POTATO.equals(mat)) {
|
||||
event.setExpToDrop(0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin().log(Level.WARNING, "Failed to stop potato XP", e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disableVillagerTrading(PlayerInteractEntityEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isVillagerTrading()) {
|
||||
Entity npc = event.getRightClicked();
|
||||
// Don't recall specifically but considering I had this null check
|
||||
// alone... I probably had an NPE here at some point. Probably plugin
|
||||
// with plugin interactions.
|
||||
if (npc != null && EntityType.VILLAGER.equals(npc.getType())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disableWitherSpawning(CreatureSpawnEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isWitherSpawning()) {
|
||||
if (EntityType.WITHER.equals(event.getEntityType())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disablePatrols(CreatureSpawnEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isPatrolSpawning()) {
|
||||
if (event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.PATROL) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disablePhantomSpawning(CreatureSpawnEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isPhantomSpawning()) {
|
||||
if (EntityType.PHANTOM.equals(event.getEntityType())
|
||||
&& event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.NATURAL) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disableEnderChestPlacement(BlockPlaceEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isEnderChestPlacement()) {
|
||||
if (Material.ENDER_CHEST.equals(event.getBlock().getType())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disableEnderChestUse(PlayerInteractEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isEnderChestUse()) {
|
||||
Action action = event.getAction();
|
||||
Material material = event.getClickedBlock().getType();
|
||||
boolean enderChest = action == Action.RIGHT_CLICK_BLOCK &&
|
||||
Material.ENDER_CHEST.equals(material);
|
||||
if (enderChest) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disableShulkerBoxUse(InventoryOpenEvent event){
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isShulkerBoxUse() && InventoryType.SHULKER_BOX.equals(event.getInventory().getType())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void disabledShulkerBoxHoppering(InventoryMoveItemEvent event) {
|
||||
if (!config.isEnabled() || config.isShulkerBoxUse()) {
|
||||
return;
|
||||
}
|
||||
if (InventoryType.SHULKER_BOX.equals(event.getDestination().getType()) ||
|
||||
InventoryType.SHULKER_BOX.equals(event.getSource().getType())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disableTotemPowers(EntityResurrectEvent event) {
|
||||
if (!config.isEnabled() || config.isTotemPowers()) return;
|
||||
|
||||
if (EntityType.PLAYER.equals(event.getEntityType())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void disableChorusFruitTeleportation(PlayerTeleportEvent event) {
|
||||
if (!config.isEnabled() || config.isChorusFruitTeleportation()) return;
|
||||
|
||||
if (PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT.equals(event.getCause())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void weepingAngelListener(PlayerDeathEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isWeepingAngel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getEntity().getLastDamageCause() instanceof EntityDamageByEntityEvent) {
|
||||
EntityDamageByEntityEvent evt = ((EntityDamageByEntityEvent) event.getEntity().getLastDamageCause());
|
||||
LivingEntity killer = null;
|
||||
|
||||
if (evt.getDamager() instanceof LivingEntity) {
|
||||
killer = (LivingEntity) evt.getDamager();
|
||||
} else if (evt.getDamager() instanceof Projectile) {
|
||||
Projectile projectile = (Projectile) evt.getDamager();
|
||||
|
||||
if (projectile.getShooter() instanceof LivingEntity) {
|
||||
killer = (LivingEntity) projectile.getShooter();
|
||||
}
|
||||
}
|
||||
|
||||
if (killer != null) {
|
||||
if (killer instanceof Player) {
|
||||
banPlayer(event.getEntity().getPlayer(), config.getWeepingAngelPlayer());
|
||||
} else {
|
||||
banPlayer(event.getEntity().getPlayer(), config.getWeepingAngelEnv());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
banPlayer(event.getEntity().getPlayer(), config.getWeepingAngelEnv());
|
||||
}
|
||||
}
|
||||
|
||||
private void banPlayer(final Player player, final int banTimeMS) {
|
||||
if (!config().isWeepingAngel()) {
|
||||
return;
|
||||
}
|
||||
final String banLengthMessage;
|
||||
if (banTimeMS < 60_000) { // 1 Minute
|
||||
final var seconds = TimeUnit.MILLISECONDS.toSeconds(banTimeMS);
|
||||
if (seconds == 1) {
|
||||
banLengthMessage = "1 second";
|
||||
}
|
||||
else {
|
||||
banLengthMessage = seconds + " seconds";
|
||||
}
|
||||
}
|
||||
else {
|
||||
final var minutes = TimeUnit.MILLISECONDS.toMinutes(banTimeMS);
|
||||
if (minutes == 1) {
|
||||
banLengthMessage = "1 minute";
|
||||
}
|
||||
else {
|
||||
banLengthMessage = minutes + " minutes";
|
||||
}
|
||||
}
|
||||
player.banPlayer(
|
||||
// Ban Message
|
||||
"You've been banned for " + banLengthMessage + " due to your death.",
|
||||
// Ban Expiry
|
||||
DateUtils.addMilliseconds(new Date(), banTimeMS),
|
||||
// Ban Source
|
||||
"Death",
|
||||
// Kick Player If Online
|
||||
true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPlayerBucketEmptyEvent(PlayerBucketEmptyEvent e) {
|
||||
if (config.isEnabled() && config.isBlockWaterInHell()) {
|
||||
if (Biome.NETHER_WASTES.equals(e.getBlockClicked().getBiome()) && Material.WATER_BUCKET.equals(e.getBucket())) {
|
||||
e.setCancelled(true);
|
||||
e.getItemStack().setType(Material.BUCKET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onDispenseEvent(BlockDispenseEvent event) {
|
||||
if (!config.isEnabled() || !config.isBlockWaterInHell()) {
|
||||
return;
|
||||
}
|
||||
if (Material.DISPENSER.equals(event.getBlock().getType())) {
|
||||
Dispenser disp = (Dispenser) event.getBlock().getBlockData();
|
||||
Biome biome = event.getBlock().getRelative(disp.getFacing()).getBiome();
|
||||
if (Biome.NETHER_WASTES.equals(biome) && Material.WATER_BUCKET.equals(event.getItem().getType())) {
|
||||
event.setItem(new ItemStack(Material.BUCKET, event.getItem().getAmount()));
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
if (config.isEnabled() && config.isMinecartTeleport()) {
|
||||
Player player = event.getPlayer();
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (vehicle == null) {
|
||||
return;
|
||||
}
|
||||
Location vehicleLocation = vehicle.getLocation();
|
||||
player.leaveVehicle();
|
||||
if (!TeleportUtil.tryToTeleportVertically(player, vehicleLocation, "logged out")) {
|
||||
player.setHealth(0.000000D);
|
||||
plugin().log(Level.INFO, "Player '%s' logged out in vehicle: killed", player.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onVehicleExit(VehicleExitEvent event) {
|
||||
if (config.isEnabled() && config.isMinecartTeleport()) {
|
||||
final Vehicle vehicle = event.getVehicle();
|
||||
final Entity passenger = event.getExited();
|
||||
if (!(passenger instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
final Player player = (Player) passenger;
|
||||
final Location vehicleLocation = vehicle.getLocation();
|
||||
Bukkit.getScheduler().runTaskLater(plugin(), () -> {
|
||||
if (!TeleportUtil.tryToTeleportVertically(player, vehicleLocation, "exiting vehicle")) {
|
||||
player.setHealth(0.000000D);
|
||||
plugin().log(Level.INFO, "Player '%s' exiting vehicle: killed", player.getName());
|
||||
}
|
||||
}, 2L);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onVehicleDestroy(VehicleDestroyEvent event) {
|
||||
if (config.isEnabled() && config.isMinecartTeleport()) {
|
||||
final Vehicle vehicle = event.getVehicle();
|
||||
final List<Entity> passengers = vehicle.getPassengers();
|
||||
if (passengers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final Location vehicleLocation = vehicle.getLocation();
|
||||
passengers.removeIf((passenger -> !(passenger instanceof Player)));
|
||||
passengers.forEach((passenger) -> {
|
||||
final Player player = (Player) passenger;
|
||||
Bukkit.getScheduler().runTaskLater(plugin(), () -> {
|
||||
if (!TeleportUtil.tryToTeleportVertically(player, vehicleLocation, "in destroyed vehicle")) {
|
||||
player.setHealth(0.000000D);
|
||||
plugin().log(Level.INFO, String.format("Player '%s' exiting vehicle: killed", player.getName()));
|
||||
}
|
||||
}, 2L);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockFromTo(BlockFromToEvent event) {
|
||||
if (config.isEnabled() && config.isObsidianGenerators()) {
|
||||
if (Material.LAVA.equals(event.getBlock().getType())) {
|
||||
Block to = event.getToBlock();
|
||||
if (Material.REDSTONE.equals(to.getType()) || Material.TRIPWIRE.equals(to.getType())) {
|
||||
if (Material.WATER.equals(to.getRelative(BlockFace.NORTH).getType())
|
||||
|| Material.WATER.equals(to.getRelative(BlockFace.SOUTH).getType())
|
||||
|| Material.WATER.equals(to.getRelative(BlockFace.WEST).getType())
|
||||
|| Material.WATER.equals(to.getRelative(BlockFace.EAST).getType())) {
|
||||
event.setCancelled(true);
|
||||
to.setType(Material.OBSIDIAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||
if (!config.isEnabled() || !config.isPersonalDeathMessages()) {
|
||||
return;
|
||||
}
|
||||
event.setDeathMessage(null);
|
||||
Player dead = event.getEntity();
|
||||
String killer = "";
|
||||
Location loc = dead.getLocation();
|
||||
if (dead.getKiller() != null) {
|
||||
killer = dead.getKiller().getDisplayName();
|
||||
dead.sendMessage(ChatColor.RED + String.format("You were slain by player %s at [%s %d, %d, %d]",
|
||||
killer, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
killer = dead.getLastDamageCause().getCause().toString();
|
||||
} catch (NullPointerException e) {
|
||||
return;
|
||||
}
|
||||
dead.sendMessage(ChatColor.RED + String.format("You were slain by %s at [%s %d, %d, %d]",
|
||||
killer, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void netheriteCrafting(PrepareSmithingEvent event) {
|
||||
if (!config.isEnabled() || !config.isDisableNetheriteCrafting()) {
|
||||
return;
|
||||
}
|
||||
//This purely disables vanilla netherite crafting in smithing tables ONLY
|
||||
SmithingInventory smithingTable = event.getInventory();
|
||||
ItemStack result = smithingTable.getResult();
|
||||
if (!ItemUtils.isValidItem(result)) {
|
||||
return;
|
||||
}
|
||||
switch (result.getType()) {
|
||||
case NETHERITE_HELMET:
|
||||
case NETHERITE_CHESTPLATE:
|
||||
case NETHERITE_LEGGINGS:
|
||||
case NETHERITE_BOOTS:
|
||||
case NETHERITE_PICKAXE:
|
||||
case NETHERITE_SHOVEL:
|
||||
case NETHERITE_AXE:
|
||||
case NETHERITE_HOE:
|
||||
case NETHERITE_SWORD:
|
||||
event.setResult(new ItemStack(Material.AIR));
|
||||
Bukkit.getScheduler().runTask(this.plugin, () -> {
|
||||
for (Player player : InventoryUtils.getViewingPlayers(smithingTable)) {
|
||||
player.updateInventory();
|
||||
player.sendMessage(ChatColor.RED + "Vanilla netherite crafting is disabled!");
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
+546
@@ -0,0 +1,546 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.GameFixesConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.PacketManager;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.type.Dispenser;
|
||||
import org.bukkit.block.data.type.Hopper;
|
||||
import org.bukkit.block.data.type.RespawnAnchor;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockDispenseEvent;
|
||||
import org.bukkit.event.block.BlockFormEvent;
|
||||
import org.bukkit.event.block.BlockPistonExtendEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.block.SignChangeEvent;
|
||||
import org.bukkit.event.entity.EntityPortalEvent;
|
||||
import org.bukkit.event.entity.EntityTeleportEvent;
|
||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.bukkit.event.world.StructureGrowEvent;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
public class GameFixes extends SimpleHack<GameFixesConfig> implements Listener {
|
||||
|
||||
public static final String NAME = "GameFixes";
|
||||
|
||||
private final PacketManager protocol = new PacketManager();
|
||||
|
||||
public GameFixes(SimpleAdminHacks plugin, GameFixesConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.protocol.removeAllAdapters();
|
||||
HandlerList.unregisterAll(this);
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
StringBuilder genStatus = new StringBuilder();
|
||||
genStatus.append("GameFixes is ");
|
||||
if (config != null && config.isEnabled()) {
|
||||
genStatus.append(ChatColor.GREEN).append("active\n").append(ChatColor.RESET);
|
||||
genStatus.append(" Block elytra break bug is ");
|
||||
if (config.isBlockElytraBreakBug()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
genStatus.append(" Will deal " + config.getDamageOnElytraBreakBug() + " damage to players\n");
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Block storage entities from teleporting to prevents exploits ");
|
||||
if (!config.canStorageTeleport()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Hopper self-feed duplication exploit fix ");
|
||||
if (config.isStopHopperDupe()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Duplications using rails exploit fix ");
|
||||
if (config.isStopRailDupe()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" End Portal removal exploit fix ");
|
||||
if (config.isStopEndPortalDeletion()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Bed Bombing in Nether / Hell Biomes fix ");
|
||||
if (config.stopBedBombing()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Tree wraparound fix ");
|
||||
if (config.stopTreeWraparound()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Maintain flat bedrock ");
|
||||
if (config.maintainFlatBedrock()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Maintain flat bedrock ");
|
||||
if (config.maintainFlatBedrock()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Fix pearl glitches ");
|
||||
if (config.fixPearlGlitch()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
genStatus.append(" Prevent long signs ");
|
||||
if (config.isPreventLongSigns()) {
|
||||
genStatus.append(ChatColor.GREEN).append("enabled\n").append(ChatColor.RESET);
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("disabled\n").append(ChatColor.RESET);
|
||||
}
|
||||
} else {
|
||||
genStatus.append(ChatColor.RED).append("inactive").append(ChatColor.RESET);
|
||||
}
|
||||
return genStatus.toString();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
if (!config.isEnabled() || !config.isBlockElytraBreakBug()) return;
|
||||
Block block = event.getBlock();
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (!player.getLocation().equals(block.getLocation())
|
||||
&& player.getEyeLocation().getBlock().getType() != Material.AIR) {
|
||||
event.setCancelled(true);
|
||||
player.damage(config.getDamageOnElytraBreakBug());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onEntityTeleport(EntityTeleportEvent event) {
|
||||
if (!config.isEnabled() || config.canStorageTeleport()) {
|
||||
return;
|
||||
}
|
||||
if (event.getEntity() instanceof InventoryHolder) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onEntityPortal(EntityPortalEvent event) {
|
||||
if (!config.isEnabled() || config.canStorageTeleport()) {
|
||||
return;
|
||||
}
|
||||
if (event.getEntity() instanceof InventoryHolder) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
|
||||
if (!config.isEnabled() || !config.isStopHopperDupe()) return;
|
||||
// I recollect inventory handling to be the single biggest source of NPEs, so I'll add
|
||||
// back in the nullcheck, although I do hope Spigot has addressed the sources with the
|
||||
// addition of their annotations.
|
||||
//
|
||||
if ((event.getDestination() == null) || (event.getSource() == null) ||
|
||||
!(InventoryType.HOPPER.equals(event.getDestination().getType())) ||
|
||||
!(InventoryType.HOPPER.equals(event.getSource().getType())) ||
|
||||
!(Material.HOPPER.equals(event.getDestination().getLocation().getBlock().getType())) ||
|
||||
!(Material.HOPPER.equals(event.getSource().getLocation().getBlock().getType()))) {
|
||||
return;
|
||||
}
|
||||
Hopper source = (Hopper) event.getSource().getLocation().getBlock().getBlockData();
|
||||
Hopper dest = (Hopper) event.getDestination().getLocation().getBlock().getBlockData();
|
||||
if (source.getFacing().getOppositeFace() == dest.getFacing()) {
|
||||
//They're pointing into each other and will eventually dupe
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onPistonPushRail(BlockPistonExtendEvent event) {
|
||||
if (config.isEnabled() && config.isStopRailDupe()) {
|
||||
for (Block block : event.getBlocks()) {
|
||||
Material type = block.getType();
|
||||
|
||||
if (config.getRailArray().contains(type)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onRailPlace(BlockPlaceEvent event) {
|
||||
if (config.isEnabled() && config.isStopRailDupe()) {
|
||||
Block block = event.getBlock();
|
||||
Material type = block.getType();
|
||||
|
||||
if (config.getRailArray().contains(type)) {
|
||||
for (BlockFace face : config.getBfArray()) {
|
||||
type = block.getRelative(face).getType();
|
||||
|
||||
if (config.getPistonArray().contains(type)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Trying to stop players from deleting end portals
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
|
||||
if (config.isEnabled() && config.isStopEndPortalDeletion()) {
|
||||
Block block = event.getBlockClicked().getRelative(event.getBlockFace());
|
||||
|
||||
if (Material.END_PORTAL.equals(block.getType())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onDispenseEvent(BlockDispenseEvent event) {
|
||||
if (config.isEnabled() && config.isStopEndPortalDeletion()) {
|
||||
if (Material.DISPENSER.equals(event.getBlock().getType())) {
|
||||
Dispenser disp = (Dispenser) event.getBlock().getBlockData();
|
||||
Material type = event.getBlock().getRelative(disp.getFacing()).getType();
|
||||
|
||||
if (Material.END_PORTAL.equals(type)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerEnterBed(BlockPlaceEvent event) {
|
||||
if (!config.isEnabled() || !config.stopBedBombing()) return;
|
||||
|
||||
Block b = event.getBlock();
|
||||
switch (b.getType()) {
|
||||
case BLACK_BED:
|
||||
case BLUE_BED:
|
||||
case BROWN_BED:
|
||||
case CYAN_BED:
|
||||
case GRAY_BED:
|
||||
case GREEN_BED:
|
||||
case LIME_BED:
|
||||
case MAGENTA_BED:
|
||||
case LIGHT_GRAY_BED:
|
||||
case PURPLE_BED:
|
||||
case PINK_BED:
|
||||
case YELLOW_BED:
|
||||
case WHITE_BED:
|
||||
case RED_BED:
|
||||
case ORANGE_BED:
|
||||
case LIGHT_BLUE_BED:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
Environment env = b.getLocation().getWorld().getEnvironment();
|
||||
Biome biome = b.getLocation().getBlock().getBiome();
|
||||
if (Environment.NETHER.equals(env) || Environment.THE_END.equals(env) || Biome.NETHER_WASTES.equals(biome)
|
||||
|| Biome.END_BARRENS.equals(biome) || Biome.END_HIGHLANDS.equals(biome)
|
||||
|| Biome.END_MIDLANDS.equals(biome) || Biome.SMALL_END_ISLANDS.equals(biome)
|
||||
|| Biome.THE_END.equals(biome)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onAnchorInteraction(PlayerInteractEvent event) {
|
||||
if (!config.isEnabled() || !config.stopAnchorBombing()) {
|
||||
return;
|
||||
}
|
||||
if (event.getClickedBlock() == null) {
|
||||
return;
|
||||
}
|
||||
if (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
if (!event.getClickedBlock().getType().equals(Material.RESPAWN_ANCHOR)) {
|
||||
return;
|
||||
}
|
||||
RespawnAnchor anchor = (RespawnAnchor) event.getClickedBlock().getBlockData();
|
||||
if (!event.getMaterial().equals(Material.GLOWSTONE)) {
|
||||
event.setCancelled(true);
|
||||
} else if (anchor.getCharges() == anchor.getMaximumCharges()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
event.getPlayer().sendMessage(ChatColor.RED + "Respawn anchor bombing is disabled");
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true)
|
||||
public void onStructureGrow(StructureGrowEvent event) {
|
||||
if(config.isEnabled() && config.stopTreeWraparound()) {
|
||||
int maxY = 0;
|
||||
int minY = 257;
|
||||
for(BlockState bs : event.getBlocks()) {
|
||||
final int y = bs.getLocation().getBlockY();
|
||||
maxY = Math.max(maxY, y);
|
||||
minY = Math.min(minY, y);
|
||||
}
|
||||
if(maxY - minY > 240) {
|
||||
event.setCancelled(true);
|
||||
final Location loc = event.getLocation();
|
||||
plugin().log(Level.INFO, String.format("Prevented structure wraparound at %s: %d, %d, %d",
|
||||
loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onTouchBedrock(PlayerInteractEvent event) {
|
||||
if(config.isEnabled() && config.maintainFlatBedrock() && event.getClickedBlock() != null
|
||||
&& event.getClickedBlock().getType() == Material.BEDROCK && event.getClickedBlock().getY() > 0) {
|
||||
Bukkit.getScheduler().runTask(plugin(), () -> {
|
||||
event.getClickedBlock().setType(Material.STONE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onPearlTeleport(PlayerTeleportEvent event) {
|
||||
if(config.isEnabled() && config.fixPearlGlitch() && event.getCause() == TeleportCause.ENDER_PEARL) {
|
||||
Location to = event.getTo();
|
||||
World world = to.getWorld();
|
||||
|
||||
Block toBlock = to.getBlock();
|
||||
Block above = toBlock.getRelative(BlockFace.UP);
|
||||
Block below = toBlock.getRelative(BlockFace.DOWN);
|
||||
boolean lowerBlockBypass = false;
|
||||
double height = 0.0;
|
||||
switch (toBlock.getType()) {
|
||||
case CHEST:
|
||||
case ENDER_CHEST:
|
||||
height = 0.875;
|
||||
break;
|
||||
case ACACIA_SLAB:
|
||||
case ANDESITE_SLAB:
|
||||
case BIRCH_SLAB:
|
||||
case BRICK_SLAB:
|
||||
case COBBLESTONE_SLAB:
|
||||
case CUT_RED_SANDSTONE_SLAB:
|
||||
case CUT_SANDSTONE_SLAB:
|
||||
case DARK_OAK_SLAB:
|
||||
case DARK_PRISMARINE_SLAB:
|
||||
case DIORITE_SLAB:
|
||||
case END_STONE_BRICK_SLAB:
|
||||
case GRANITE_SLAB:
|
||||
case JUNGLE_SLAB:
|
||||
case MOSSY_COBBLESTONE_SLAB:
|
||||
case STONE_SLAB:
|
||||
case STONE_BRICK_SLAB:
|
||||
case SPRUCE_SLAB:
|
||||
case SMOOTH_STONE_SLAB:
|
||||
case SMOOTH_SANDSTONE_SLAB:
|
||||
case SMOOTH_RED_SANDSTONE_SLAB:
|
||||
case SMOOTH_QUARTZ_SLAB:
|
||||
case SANDSTONE_SLAB:
|
||||
case RED_SANDSTONE_SLAB:
|
||||
case RED_NETHER_BRICK_SLAB:
|
||||
case QUARTZ_SLAB:
|
||||
case PURPUR_SLAB:
|
||||
case PRISMARINE_SLAB:
|
||||
case PRISMARINE_BRICK_SLAB:
|
||||
case POLISHED_GRANITE_SLAB:
|
||||
case POLISHED_DIORITE_SLAB:
|
||||
case POLISHED_ANDESITE_SLAB:
|
||||
case PETRIFIED_OAK_SLAB:
|
||||
case OAK_SLAB:
|
||||
case NETHER_BRICK_SLAB:
|
||||
case MOSSY_STONE_BRICK_SLAB:
|
||||
lowerBlockBypass = true;
|
||||
height = 0.5;
|
||||
break;
|
||||
case LILY_PAD:
|
||||
height = 0.016;
|
||||
break;
|
||||
case ENCHANTING_TABLE:
|
||||
lowerBlockBypass = true;
|
||||
height = 0.75;
|
||||
break;
|
||||
case BLACK_BED:
|
||||
case BLUE_BED:
|
||||
case BROWN_BED:
|
||||
case CYAN_BED:
|
||||
case GRAY_BED:
|
||||
case GREEN_BED:
|
||||
case LIME_BED:
|
||||
case MAGENTA_BED:
|
||||
case LIGHT_GRAY_BED:
|
||||
case PURPLE_BED:
|
||||
case PINK_BED:
|
||||
case YELLOW_BED:
|
||||
case WHITE_BED:
|
||||
case RED_BED:
|
||||
case ORANGE_BED:
|
||||
case LIGHT_BLUE_BED:
|
||||
break;
|
||||
case FLOWER_POT:
|
||||
height = 0.375;
|
||||
break;
|
||||
case SKELETON_SKULL:
|
||||
case WITHER_SKELETON_WALL_SKULL:
|
||||
case WITHER_SKELETON_SKULL:
|
||||
case SKELETON_WALL_SKULL:
|
||||
case PLAYER_HEAD:
|
||||
case PLAYER_WALL_HEAD:
|
||||
case CREEPER_HEAD:
|
||||
case CREEPER_WALL_HEAD:
|
||||
case DRAGON_HEAD:
|
||||
case DRAGON_WALL_HEAD:
|
||||
case ZOMBIE_HEAD:
|
||||
case ZOMBIE_WALL_HEAD:
|
||||
height = 0.5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (below.getType()) {
|
||||
case ACACIA_FENCE:
|
||||
case ACACIA_FENCE_GATE:
|
||||
case BIRCH_FENCE:
|
||||
case BIRCH_FENCE_GATE:
|
||||
case DARK_OAK_FENCE:
|
||||
case DARK_OAK_FENCE_GATE:
|
||||
case JUNGLE_FENCE:
|
||||
case JUNGLE_FENCE_GATE:
|
||||
case SPRUCE_FENCE_GATE:
|
||||
case SPRUCE_FENCE:
|
||||
case OAK_FENCE_GATE:
|
||||
case OAK_FENCE:
|
||||
case NETHER_BRICK_FENCE:
|
||||
case ANDESITE_WALL:
|
||||
case BRICK_WALL:
|
||||
case STONE_BRICK_WALL:
|
||||
case COBBLESTONE_WALL:
|
||||
case DIORITE_WALL:
|
||||
case END_STONE_BRICK_WALL:
|
||||
case GRANITE_WALL:
|
||||
case SANDSTONE_WALL:
|
||||
case RED_SANDSTONE_WALL:
|
||||
case MOSSY_COBBLESTONE_WALL:
|
||||
case MOSSY_STONE_BRICK_WALL:
|
||||
case PRISMARINE_WALL:
|
||||
case RED_NETHER_BRICK_WALL:
|
||||
case NETHER_BRICK_WALL:
|
||||
height = 0.5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
boolean upperBlockBypass = false;
|
||||
if (height >= 0.5) {
|
||||
Block aboveHeadBlock = above.getRelative(BlockFace.UP);
|
||||
if (!aboveHeadBlock.getType().isSolid()) {
|
||||
height = 0.5;
|
||||
} else {
|
||||
upperBlockBypass = true;
|
||||
}
|
||||
}
|
||||
|
||||
to.setX(Math.floor(to.getX() + 0.5000));
|
||||
to.setY(Math.floor(to.getY() + height));
|
||||
to.setZ(Math.floor(to.getZ() + 0.5000));
|
||||
|
||||
if (above.getType().isSolid() || (toBlock.getType().isSolid() && !lowerBlockBypass)
|
||||
|| upperBlockBypass) {
|
||||
boolean bypass = false;
|
||||
if (world.getEnvironment() == Environment.NETHER &&
|
||||
to.getBlockY() > 124 && to.getBlockY() < 129) {
|
||||
bypass = true;
|
||||
}
|
||||
if (!bypass) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//fixes a small side effect of the above
|
||||
BlockFace[] faces = new BlockFace[] {BlockFace.NORTH,BlockFace.SOUTH,BlockFace.EAST,BlockFace.WEST};
|
||||
@EventHandler
|
||||
public void preventWrongIce(BlockFormEvent event) {
|
||||
Block block = event.getBlock();
|
||||
if(event.getNewState().getType() == Material.ICE) {
|
||||
for(BlockFace face : faces) {
|
||||
if(block.getRelative(face).getType().isSolid()) return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onSignChange(SignChangeEvent event) {
|
||||
if(config.isEnabled() && config.isPreventLongSigns()) {
|
||||
String[] signdata = event.getLines();
|
||||
for(int i = 0; i < signdata.length; i++) {
|
||||
if(signdata[i] != null && signdata[i].length() > config.getSignLengthLimit()) {
|
||||
Player player = event.getPlayer();
|
||||
Location loc = event.getBlock().getLocation();
|
||||
plugin().log(Level.WARNING, String.format("Player '%s' [%s] attempted to place sign at ([%s] %d, %d, %d) with line %d having length %d > %d. Preventing.",
|
||||
player.getDisplayName(), player.getUniqueId(), loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(),
|
||||
i, signdata[i], config.getSignLengthLimit()));
|
||||
if(config.isCancelLongSignEvent()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if(config.isPreventLongSignsAbsolute()) {
|
||||
event.setLine(i, "");
|
||||
} else {
|
||||
event.setLine(i, signdata[i].substring(0, config.getSignLengthLimit()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static GameFixesConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new GameFixesConfig(plugin, config);
|
||||
}
|
||||
|
||||
}
|
||||
+487
@@ -0,0 +1,487 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.GameTuningConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.TeleportUtil;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import javax.annotation.Nonnull;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Skeleton;
|
||||
import org.bukkit.entity.SkeletonHorse;
|
||||
import org.bukkit.entity.minecart.HopperMinecart;
|
||||
import org.bukkit.entity.minecart.StorageMinecart;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockPistonExtendEvent;
|
||||
import org.bukkit.event.block.BlockPistonRetractEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
import org.bukkit.event.entity.EntityPortalEvent;
|
||||
import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
import org.bukkit.event.entity.EntityTargetEvent;
|
||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent.BedEnterResult;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerPortalEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.weather.WeatherChangeEvent;
|
||||
import org.bukkit.event.world.PortalCreateEvent;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.meta.SpawnEggMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;
|
||||
|
||||
/**
|
||||
* This is a grab-bag class to hold any _tuning_ related configurations that impact the
|
||||
* game, server-wide.
|
||||
*
|
||||
* It's part of a series of focused hacks.
|
||||
*
|
||||
* {@link GameFixes} is focused on things that are broken or don't work, and attempts to fix them.
|
||||
* {@link GameFeatures} focuses on enabling and disabling features, like elytra, various potion states.
|
||||
* {@link GameTuning} neither fixes nor disables, but rather adjusts and reconfigures.
|
||||
*
|
||||
* Currently you can control the following:
|
||||
* - BlockEntity limits per chunk
|
||||
* - Setting bed during the day instead of just at night
|
||||
*/
|
||||
public class GameTuning extends SimpleHack<GameTuningConfig> implements Listener, CommandExecutor {
|
||||
public static final String NAME = "GameTuning";
|
||||
|
||||
public GameTuning(SimpleAdminHacks plugin, GameTuningConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config != null && config.isEnabled()) {
|
||||
plugin().log("Registering GameTuning listeners");
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
// Bukkit does this for us.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
if (config.isEnabled()) {
|
||||
plugin.registerCommand("chunklimits", this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
StringBuilder genStatus = new StringBuilder();
|
||||
genStatus.append("GameTuning is ");
|
||||
if (config != null && config.isEnabled()) {
|
||||
genStatus.append("active\n");
|
||||
if (config.areChunkLimitsEnabled()) {
|
||||
genStatus.append(" Chunk Limits are enabled\n");
|
||||
} else {
|
||||
genStatus.append(" Chunk Limits are disabled\n");
|
||||
}
|
||||
if (config.areDaytimeBedsEnabled()) {
|
||||
genStatus.append(" Daytime Beds are enabled\n");
|
||||
} else {
|
||||
genStatus.append(" Daytime Beds are disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" One To One Nether is ");
|
||||
if (config.isOneToOneNether()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
genStatus.append(" Stop trap horses is ");
|
||||
if (config.stopTrapHorses()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Kill trap horses is ");
|
||||
if (config.killTrapHorses()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Changing spawner type is ");
|
||||
if (config.canChangeSpawnerType()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Villager trading is ");
|
||||
if (config.allowVillagerTrading()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Ender grief is ");
|
||||
if (config.isEnderGrief()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Wither grief is ");
|
||||
if (config.isWitherGrief()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Dragon grief is ");
|
||||
if (config.isDragonGrief()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Prevent falling through bedrock is ");
|
||||
if (config.isPreventFallingThroughBedrock()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Bad Omen is ");
|
||||
if (config.isBadOmenEnabled()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
genStatus.append(" Rain reduction is ");
|
||||
if (config.isRainReductionEnabled()) {
|
||||
genStatus.append("enabled\n");
|
||||
} else {
|
||||
genStatus.append("disabled\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
genStatus.append("inactive");
|
||||
}
|
||||
return genStatus.toString();
|
||||
}
|
||||
|
||||
public static GameTuningConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new GameTuningConfig(plugin, config);
|
||||
}
|
||||
|
||||
/* From here on, the actual meat of the hack. Above is basically boilerplate for micro-plugins.*/
|
||||
|
||||
/**
|
||||
* Many thanks to BlackXNT for his work on this event in Humbug, which I have largely copied and expanded.
|
||||
*
|
||||
* This tracks block placements, and if a limit is configured and the block is a TileEntity w/ state,
|
||||
* will reject the placement if otherwise it would exceed limits for the Chunk.
|
||||
*
|
||||
* @param event the Placement event.
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void chunkLimits(BlockPlaceEvent event) {
|
||||
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
|
||||
try {
|
||||
Player player = event.getPlayer();
|
||||
Block block = event.getBlock();
|
||||
|
||||
if (!config.applyChunkLimits(player.getUniqueId())) return;
|
||||
|
||||
Material mat = block.getType();
|
||||
|
||||
Integer limit = config.getChunkLimit(mat);
|
||||
if (limit == null) return;
|
||||
|
||||
int current = 0;
|
||||
for (BlockState state : block.getChunk().getTileEntities()) {
|
||||
if (state != null && mat.equals(state.getType())) {
|
||||
if (++current > limit) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage(config.getChunkLimitsExceededMessage()
|
||||
.replaceAll("%Limit%",Integer.toString(limit))
|
||||
.replaceAll("%Material%", ItemUtils.getItemName(mat))
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin().log(Level.WARNING, "Failed to measure chunk limit", e);
|
||||
}
|
||||
}
|
||||
|
||||
// If any limit at all, cancel the piston event.
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void chunkLimitsExploitExtend(BlockPistonExtendEvent event) {
|
||||
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
|
||||
List<Block> blocks = event.getBlocks();
|
||||
if (!blocks.isEmpty()) {
|
||||
for (Block b : blocks) {
|
||||
if (b != null && config.getChunkLimit(b.getType()) != null) {
|
||||
event.setCancelled(true);
|
||||
return; // TODO send message to nearby player warning of reason for stopping.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Yes, this is identical ...
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void chunkLimitsExploitRetract(BlockPistonRetractEvent event) {
|
||||
if (!config.isEnabled() || !config.areChunkLimitsEnabled()) return;
|
||||
List<Block> blocks = event.getBlocks();
|
||||
if (!blocks.isEmpty()) {
|
||||
for (Block b : blocks) {
|
||||
if (b != null && config.getChunkLimit(b.getType()) != null) {
|
||||
event.setCancelled(true);
|
||||
return; // TODO send message to nearby player warning of reason for stopping.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void enterBed(PlayerBedEnterEvent e) {
|
||||
if (!config.isEnabled() || !config.areDaytimeBedsEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (BedEnterResult.NOT_POSSIBLE_NOW.equals(e.getBedEnterResult()) || BedEnterResult.NOT_SAFE.equals(e.getBedEnterResult())) {
|
||||
e.getPlayer().setBedSpawnLocation(e.getBed().getLocation(), false);
|
||||
e.getPlayer().sendTitle("", config.getDaytimeBedSpawnSetMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPortalTravel(EntityPortalEvent event) {
|
||||
if (!config.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (!config.allowNetherTravel() && event.getTo() != null && event.getTo().getWorld().getEnvironment() == Environment.NETHER) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (config.isOneToOneNether()) {
|
||||
Location newLoc = event.getFrom();
|
||||
newLoc.setWorld(event.getTo().getWorld());
|
||||
event.setTo(newLoc);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerPortalTravel(PlayerPortalEvent event) {
|
||||
if(config.isEnabled() && PlayerTeleportEvent.TeleportCause.NETHER_PORTAL == event.getCause()) {
|
||||
if(!config.allowNetherTravel()) {
|
||||
event.setCancelled(true);
|
||||
} else if (config.isOneToOneNether()) {
|
||||
Location newLoc = event.getFrom();
|
||||
newLoc.setWorld(event.getTo().getWorld());
|
||||
event.setTo(newLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onPortalCreate(PortalCreateEvent event) {
|
||||
if (config.isEnabled() && !config.isReturnNetherPortal()) {
|
||||
if (PortalCreateEvent.CreateReason.FIRE.equals(event.getReason()) && Environment.NETHER.equals(event.getWorld().getEnvironment())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Trying to stop dupe bugs via minecart inventories
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onEntityRightClick(PlayerInteractEntityEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isChestedMinecartInventories() || !config.isHopperMinecartInventories()) {
|
||||
Entity target = event.getRightClicked();
|
||||
|
||||
if (target.getType().equals(EntityType.MINECART_CHEST) && !config.isChestedMinecartInventories()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
if (target.getType().equals(EntityType.MINECART_HOPPER) && !config.isHopperMinecartInventories()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onInventoryMoveItemEvent(InventoryMoveItemEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
if (!config.isChestedMinecartInventories() || !config.isHopperMinecartInventories()) {
|
||||
InventoryHolder holder = event.getDestination().getHolder();
|
||||
if (holder instanceof StorageMinecart && !config.isChestedMinecartInventories()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
if (holder instanceof HopperMinecart && !config.isHopperMinecartInventories()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityTarget(EntityTargetEvent event) {
|
||||
if(config.isEnabled() && config.stopTrapHorses()) {
|
||||
Entity entity = event.getEntity();
|
||||
if(entity instanceof Skeleton && entity.isInsideVehicle() && entity.getVehicle() instanceof SkeletonHorse) {
|
||||
if(config.killTrapHorses()) {
|
||||
entity.getVehicle().remove();
|
||||
}
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
if(!config.isEnabled() || !Action.RIGHT_CLICK_BLOCK.equals(event.getAction())) {
|
||||
return;
|
||||
}
|
||||
boolean cancel = !config.canChangeSpawnerType() && Material.SPAWNER.equals(event.getClickedBlock().getType())
|
||||
&& event.getItem() != null && event.getItem().getItemMeta() instanceof SpawnEggMeta;
|
||||
if (cancel) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
if(config.isEnabled() && !config.canPlace(event.getBlock().getType())) {
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage(ChatColor.RED + "You're not allowed to place that!");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
||||
if(config.isEnabled() && !config.allowVillagerTrading()) {
|
||||
Entity npc = event.getRightClicked();
|
||||
// consistency, preserving null check
|
||||
if(npc != null && EntityType.VILLAGER.equals(npc.getType())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
|
||||
if(config.isEnabled() &&
|
||||
(!config.isEnderGrief() && EntityType.ENDERMAN.equals(event.getEntityType())) ||
|
||||
(!config.isWitherGrief() && EntityType.WITHER.equals(event.getEntityType())) ||
|
||||
(!config.isDragonGrief() && EntityType.ENDER_DRAGON.equals(event.getEntityType()))) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Speculative handler for dragon fireballs and exploding wither skulls
|
||||
*
|
||||
* Some examples online prefer event.getEntity() instanceof DragonFireball and WitherSkull, could try that
|
||||
* if this does not work
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onEntityExplodeEvent(EntityExplodeEvent event) {
|
||||
if (config.isEnabled() &&
|
||||
(!config.isDragonGrief() && EntityType.DRAGON_FIREBALL.equals(event.getEntityType())) ||
|
||||
(!config.isWitherGrief() && EntityType.WITHER_SKULL.equals(event.getEntityType()))) {
|
||||
event.setCancelled(true);
|
||||
// note this might not prevent block breaks, check on that (1.14)
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
if(config.isEnabled() && config.isPreventFallingThroughBedrock() && event.getTo().getY() < event.getTo().getWorld().getMinHeight()
|
||||
&& GameMode.SURVIVAL.equals(event.getPlayer().getGameMode())) {
|
||||
TeleportUtil.tryToTeleportVertically(event.getPlayer(), event.getTo(), "falling into the void");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBadOmenEffect(EntityPotionEffectEvent event) {
|
||||
if (!config.isEnabled() || config.isBadOmenEnabled()) {
|
||||
return;
|
||||
}
|
||||
PotionEffect effect = event.getNewEffect();
|
||||
if (effect != null && effect.getType().equals(PotionEffectType.BAD_OMEN)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRain(WeatherChangeEvent event) {
|
||||
if (!config.isEnabled() || !config.isRainReductionEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (event.toWeatherState() && Math.random() >= config.getRainOccurrenceChance()) {
|
||||
event.setCancelled(true);
|
||||
plugin().getLogger().info("Rain event was cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@Nonnull CommandSender commandSender, @Nonnull Command command, @Nonnull String s, @Nonnull String[] strings) {
|
||||
Map<Material, Integer> blockLimits = config.getBlockEntityLimits();
|
||||
|
||||
StringBuilder stringB = new StringBuilder();
|
||||
|
||||
stringB.append(ChatColor.AQUA + "-- Chunk Limitations for the following blocks --\n");
|
||||
stringB.append("\n");
|
||||
|
||||
for (Map.Entry<Material, Integer> entries: blockLimits.entrySet()) {
|
||||
Material material = entries.getKey();
|
||||
Integer blockLimit = entries.getValue();
|
||||
stringB.append("" + ChatColor.WHITE + material + " : " + blockLimit+ "\n");
|
||||
}
|
||||
commandSender.sendMessage(stringB.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.HorseStatsConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.attribute.AttributeInstance;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.AbstractHorse;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Strider;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class HorseStats extends SimpleHack<HorseStatsConfig> implements Listener {
|
||||
|
||||
public HorseStats(SimpleAdminHacks plugin, HorseStatsConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onHorseStatCheck(PlayerInteractEntityEvent event) {
|
||||
if (!config.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
ItemStack item = event.getPlayer().getInventory().getItemInMainHand();
|
||||
if (!item.getType().equals(config.getHorseCheckerItem())) {
|
||||
return;
|
||||
}
|
||||
Entity entity = event.getRightClicked();
|
||||
if (entity instanceof AbstractHorse) {
|
||||
AbstractHorse horse = (AbstractHorse)entity;
|
||||
AttributeInstance attrHealth = horse.getAttribute(Attribute.GENERIC_MAX_HEALTH);
|
||||
AttributeInstance attrSpeed = horse.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
|
||||
event.getPlayer().sendMessage(String.format("%sHealth = %f, Speed = %f, Jump height = %f",
|
||||
ChatColor.YELLOW,
|
||||
attrHealth.getBaseValue(),
|
||||
attrSpeed.getBaseValue(),
|
||||
horse.getJumpStrength()));
|
||||
} else if (entity instanceof Strider) {
|
||||
Strider strider = (Strider) entity;
|
||||
AttributeInstance attrHealth = strider.getAttribute(Attribute.GENERIC_MAX_HEALTH);
|
||||
AttributeInstance attrSpeed = strider.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
|
||||
event.getPlayer().sendMessage(String.format("%sHealth = %f, Speed = %f",
|
||||
ChatColor.YELLOW,
|
||||
attrHealth.getBaseValue(),
|
||||
attrSpeed.getBaseValue()));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering HorseStats listeners");
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
|
||||
}
|
||||
|
||||
public static HorseStatsConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new HorseStatsConfig(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
return config.isEnabled() ? "HorseStats enabled." : "HorseStats disabled.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.ClassPath;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.InsightConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.plugin.EventExecutor;
|
||||
import org.bukkit.plugin.IllegalPluginAccessException;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
/**
|
||||
* Config example:
|
||||
* <code>
|
||||
* Insight:
|
||||
* enabled: true
|
||||
* into:
|
||||
* - org.bukkit.event.player
|
||||
* - org.bukkit.event.block
|
||||
* - org.bukkit.event.inventory
|
||||
* </code>
|
||||
*
|
||||
* This "into" list defines event classpaths. Events found in that classpath are
|
||||
* instrumented; listeners are reordered to put _this_ hack's listeners as first and last to run.
|
||||
*
|
||||
* These listeners bypass safe bukkit convention, Timings, and can handle
|
||||
* async or sync events.
|
||||
*
|
||||
* Can monitor not only bukkit events but also plugin / custom events; just give the
|
||||
* valid classpath.
|
||||
*
|
||||
* This bypasses the "safe" bukkit way of registering listeners for events. So it
|
||||
* also bypasses Timings.
|
||||
*
|
||||
* This is the only warning I'll give. Be careful with this and prefer to leave it off.
|
||||
*
|
||||
* Wireups only happen on restart, I'm dubious about injecting live for now.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class Insight extends SimpleHack<InsightConfig> implements CommandExecutor, Listener {
|
||||
|
||||
public static final String NAME = "Insight";
|
||||
|
||||
private Map<String, InsightStat> tracking;
|
||||
private List<Class<? extends Event>> rebounders;
|
||||
|
||||
public Insight(SimpleAdminHacks plugin, InsightConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
return args.length >= 1;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering Insight reordering hack");
|
||||
plugin().registerListener(this);
|
||||
|
||||
plugin().log("Registering Insight event instrumentations");
|
||||
|
||||
if (config.getInsightOn() == null) {
|
||||
plugin().log("No instrumentations defined, disabling.");
|
||||
this.disable();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ClassPath getSamplersPath = ClassPath.from(plugin().exposeClassLoader());
|
||||
|
||||
for (String clsPackage : config.getInsightOn()) {
|
||||
ImmutableSet<ClassPath.ClassInfo> clsInfoSet = getSamplersPath.getTopLevelClasses(clsPackage);
|
||||
if (clsInfoSet == null || clsInfoSet.isEmpty()) {
|
||||
plugin().log(Level.INFO, "Package {0} doesn't exist or is empty.", clsPackage);
|
||||
continue;
|
||||
}
|
||||
plugin().log(Level.INFO, "Scanning package {0} for events.", clsPackage);
|
||||
for (ClassPath.ClassInfo clsInfo : clsInfoSet) {
|
||||
try {
|
||||
Class<?> clazz = clsInfo.load();
|
||||
if (clazz != null && Event.class.isAssignableFrom(clazz)) {
|
||||
plugin().log(Level.INFO, "...Found event {0}, registering", clazz.getName());
|
||||
// This is some advanced shit. It also bypasses the timings, so, be careful, ok?
|
||||
plugin().getServer().getPluginManager().registerEvent((Class<? extends Event>) clazz, this, EventPriority.LOWEST, new EventExecutor() {
|
||||
@Override
|
||||
public void execute(Listener arg0, Event arg1) throws EventException {
|
||||
try {
|
||||
((Insight) arg0).start(arg1);
|
||||
} catch (Exception e) {
|
||||
// no-op, we were never here
|
||||
}
|
||||
}
|
||||
}, plugin(), true);
|
||||
plugin().getServer().getPluginManager().registerEvent((Class<? extends Event>) clazz, this, EventPriority.MONITOR, new EventExecutor() {
|
||||
@Override
|
||||
public void execute(Listener arg0, Event arg1) throws EventException {
|
||||
try {
|
||||
((Insight) arg0).end(arg1);
|
||||
} catch (Exception e) {
|
||||
// no-op, we were never here
|
||||
}
|
||||
}
|
||||
}, plugin(), true);
|
||||
rebounders.add((Class<? extends Event>) clazz);
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
plugin().log(Level.INFO, "...Unable to register event {0} due to dependency failure", clsInfo.getName());
|
||||
} catch (IllegalPluginAccessException ipae) {
|
||||
plugin().log(Level.INFO, "...Unable to register event {0}; abstract or uninstanced event", clsInfo.getName());
|
||||
} catch (Exception e) {
|
||||
plugin().log(Level.WARNING, "...Failed to complete event registration for " + clsInfo.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
plugin().log(Level.WARNING, "Failed to register event classes", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BukkitTask remap = null;
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void postPluginLoad(PluginEnableEvent e) {
|
||||
if (!config.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (remap != null) {
|
||||
remap.cancel();
|
||||
}
|
||||
|
||||
remap = Bukkit.getScheduler().runTaskLater(plugin(), new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
//event.block
|
||||
rebounders.forEach(e -> reboundHandlers(e));
|
||||
}
|
||||
}, 60l); // 3 seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* For tracked events we hijack priority ordering insertions
|
||||
* We to grab the registeredlistener array, remove all listeners
|
||||
* then readd, forcing _this_ plugin for _that_ event to be first(s) and last(s) in the list.
|
||||
*
|
||||
* @param clazz The Event class whose handlers we want to reorder
|
||||
*/
|
||||
private <T extends Event> void reboundHandlers(Class<T> clazz) {
|
||||
try {
|
||||
plugin().log(Level.INFO, "Rebound handlers for {0}", clazz.getName());
|
||||
Method method = clazz.getDeclaredMethod("getHandlerList");
|
||||
HandlerList handler = (HandlerList) method.invoke(null);
|
||||
RegisteredListener[] listeners = handler.getRegisteredListeners();
|
||||
ArrayList<RegisteredListener> newOrdering = new ArrayList<>(listeners.length);
|
||||
ArrayList<RegisteredListener> thisLow = new ArrayList<>();
|
||||
ArrayList<RegisteredListener> thisHigh = new ArrayList<>();
|
||||
for (RegisteredListener l : listeners) {
|
||||
handler.unregister(l);
|
||||
if (l.getPriority().equals(EventPriority.LOWEST)) {
|
||||
if (l.getListener().equals(this)) {
|
||||
thisLow.add(l);
|
||||
continue;
|
||||
}
|
||||
} else if (l.getPriority().equals(EventPriority.MONITOR)) {
|
||||
if (l.getListener().equals(this)) {
|
||||
thisHigh.add(l);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
newOrdering.add(l);
|
||||
}
|
||||
if (thisLow.isEmpty()) {
|
||||
plugin().log("Failed to find low-order handler!");
|
||||
}
|
||||
thisLow.addAll(newOrdering);
|
||||
if (thisHigh.isEmpty()) {
|
||||
plugin().log("Failed to find high-order handler!");
|
||||
} else {
|
||||
thisLow.addAll(thisHigh);
|
||||
}
|
||||
try {
|
||||
handler.registerAll(thisLow);
|
||||
} catch (Exception e) {
|
||||
plugin().log(Level.SEVERE, "reboundHandler failure to reassert listeners for " + clazz.getName(), e);
|
||||
handler.registerAll(Arrays.asList(listeners));
|
||||
}
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
plugin().log(Level.WARNING, "This event does not have independent handlers, skipping " + clazz.getName());
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException m) {
|
||||
plugin().log(Level.SEVERE, "Unable to retrieve handlers for " + clazz.getName(), m);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering Insight's insight command");
|
||||
plugin().registerCommand("insight", this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
if (config.isEnabled()) {
|
||||
this.tracking = new ConcurrentHashMap<>();
|
||||
this.rebounders = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
if (config.isEnabled() || this.tracking != null) {
|
||||
this.tracking.clear();
|
||||
this.tracking = null;
|
||||
this.rebounders = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
if (config.isEnabled()) {
|
||||
StringBuffer sb = new StringBuffer( "Passively providing insight into events:\n");
|
||||
|
||||
if (this.tracking != null) {
|
||||
sb.append(ChatColor.WHITE).append(String.format(" %10s %10s %10s %7s %7s %7s %7s Event\n", "Count", "Canceled", "Handlers", "Min", "Avg", "Max", "StDev"));
|
||||
this.tracking.forEach((k, v) -> {
|
||||
sb.append(String.format(" %s%10d %10d %10d %s%7d %s%7.0f %s%7d %s%7.2f ",
|
||||
ChatColor.WHITE, v.getSamples(), v.getCancels(), v.getHandlers(),
|
||||
color(v.getMin()), v.getMin(),
|
||||
color(v.getAverage()), v.getAverage(),
|
||||
color(v.getMax()), v.getMax(),
|
||||
ChatColor.WHITE, v.getStdev()));
|
||||
sb.append(ChatColor.AQUA).append(k).append("\n");
|
||||
});
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
} else {
|
||||
return "Insights fully disabled.";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 10% of tick? Green.
|
||||
* 15% of tick? Dark Green.
|
||||
* 20% of tick? Yellow
|
||||
* 30% of tick? Orange
|
||||
* 50% of tick? Dark Red
|
||||
* Above that? Red
|
||||
*
|
||||
* @param microseconds
|
||||
* @return
|
||||
*/
|
||||
private ChatColor color(long microseconds) {
|
||||
if (microseconds <= 5000) {
|
||||
return ChatColor.GREEN;
|
||||
} else if (microseconds <= 7500) {
|
||||
return ChatColor.DARK_GREEN;
|
||||
} else if (microseconds <= 10000) {
|
||||
return ChatColor.YELLOW;
|
||||
} else if (microseconds <= 15000) {
|
||||
return ChatColor.GOLD;
|
||||
} else if (microseconds <= 25000) {
|
||||
return ChatColor.DARK_RED;
|
||||
} else {
|
||||
return ChatColor.RED;
|
||||
}
|
||||
}
|
||||
|
||||
private ChatColor color(double microseconds) {
|
||||
return color((long) microseconds);
|
||||
}
|
||||
|
||||
// -- SUPPORT
|
||||
|
||||
public void start(Event event) {
|
||||
if (config.isEnabled()) {
|
||||
InsightStat insight = this.tracking.compute(event.getEventName(), (key, stat) ->
|
||||
(stat == null) ? new InsightStat() : stat
|
||||
);
|
||||
insight.begin(event.getHandlers().getRegisteredListeners().length);
|
||||
}
|
||||
}
|
||||
|
||||
public void end(Event event) {
|
||||
if (config.isEnabled()) {
|
||||
InsightStat insight = this.tracking.get(event.getEventName());
|
||||
if (insight != null) {
|
||||
if (event instanceof Cancellable) {
|
||||
insight.end(((Cancellable) event).isCancelled());
|
||||
} else {
|
||||
insight.end(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static InsightConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new InsightConfig(plugin, config);
|
||||
}
|
||||
|
||||
private static class InsightStat {
|
||||
// count of events
|
||||
private long count;
|
||||
// count of cancels
|
||||
private long cancels;
|
||||
// avg length of event (based on LOWEST vs. MONITOR)
|
||||
private double avg;
|
||||
// max length of event (based on LOWEST vs. MONITOR)
|
||||
private long max;
|
||||
// min length of event
|
||||
private long min;
|
||||
// variance of lengths
|
||||
private double varsum;
|
||||
private double var;
|
||||
// rolling stdev of lengths
|
||||
private double std;
|
||||
// last execution handler list size
|
||||
private long handlers;
|
||||
|
||||
private long lastStart;
|
||||
|
||||
public InsightStat() {
|
||||
count = 0l;
|
||||
cancels = 0l;
|
||||
avg = 0l;
|
||||
max = 0l;
|
||||
min = 0l;
|
||||
var = 0l;
|
||||
std = 0l;
|
||||
handlers = 0l;
|
||||
lastStart = 0l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a specific capture for this; assumes runs in LOWEST for same-event.
|
||||
* Will safely skip events that had no end() called.
|
||||
*
|
||||
* @param handlers
|
||||
*/
|
||||
public synchronized void begin(long handlers) {
|
||||
this.lastStart = System.nanoTime() / 1000l;
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a specific capture for this; assumes runs in MONITOR for same-event.
|
||||
*/
|
||||
public synchronized void end(boolean cancelled) {
|
||||
long len = (System.nanoTime() / 1000l) - this.lastStart;
|
||||
if (cancelled) {
|
||||
cancels ++;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
avg = len;
|
||||
max = len;
|
||||
min = len;
|
||||
varsum = 0d;
|
||||
var = 0d;
|
||||
std = 0d;
|
||||
} else {
|
||||
double oavg = avg;
|
||||
avg = avg + ( len - avg )/ (double) (count + 1);
|
||||
// estimate...
|
||||
varsum += Math.pow(len - avg, 2);
|
||||
var = varsum / count; // (pre-inc, see Bessel's correction)
|
||||
std = Math.sqrt(var);
|
||||
if (len > max) {
|
||||
max = len;
|
||||
}
|
||||
if (len < min) {
|
||||
min = len;
|
||||
}
|
||||
}
|
||||
count++; // n+1
|
||||
}
|
||||
|
||||
public long getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public double getAverage() {
|
||||
return avg;
|
||||
}
|
||||
|
||||
public long getSamples() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public double getStdev() {
|
||||
return std;
|
||||
}
|
||||
|
||||
public long getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public long getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public long getCancels() {
|
||||
return cancels;
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-26
@@ -1,15 +1,18 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.IntrobookConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -21,23 +24,18 @@ import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BookMeta;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.CommandListener;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.IntrobookConfig;
|
||||
|
||||
/**
|
||||
* Simple Hack that handles gifting introbooks if enabled. Handles respawns as well
|
||||
* through first restart, effectively.
|
||||
*
|
||||
* @author ProgrammerDan <programmerdan@gmail.com
|
||||
* @author ProgrammerDan programmerdan@gmail.com
|
||||
*
|
||||
*/
|
||||
public class Introbook extends SimpleHack<IntrobookConfig> implements Listener, CommandExecutor {
|
||||
|
||||
public static final String NAME = "Introbook";
|
||||
private static long bookGiftCount = 0l;
|
||||
|
||||
|
||||
private Set<UUID> hasBook;
|
||||
|
||||
public Introbook(SimpleAdminHacks plugin, IntrobookConfig config) {
|
||||
@@ -83,13 +81,13 @@ public class Introbook extends SimpleHack<IntrobookConfig> implements Listener,
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void determineBookDrop(PlayerDeathEvent event) {
|
||||
if (!config.isEnabled() || !config.doesFollow()) return;
|
||||
|
||||
|
||||
Player dead = event.getEntity();
|
||||
if (dead == null) return;
|
||||
|
||||
|
||||
UUID puid = dead.getUniqueId();
|
||||
if (puid == null) return;
|
||||
|
||||
|
||||
// Check if they have the book on them.
|
||||
List<ItemStack> toDrop = event.getDrops();
|
||||
for (int idx = 0; idx < toDrop.size(); idx++) {
|
||||
@@ -105,33 +103,33 @@ public class Introbook extends SimpleHack<IntrobookConfig> implements Listener,
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void determineBookRespawn(PlayerRespawnEvent event) {
|
||||
if (!config.isEnabled() || !config.doesFollow()) return;
|
||||
|
||||
|
||||
Player dead = event.getPlayer();
|
||||
if (dead == null) return;
|
||||
|
||||
|
||||
UUID puid = dead.getUniqueId();
|
||||
if (puid == null) return;
|
||||
|
||||
|
||||
if (this.hasBook.remove(puid)) {
|
||||
Inventory inv = dead.getInventory();
|
||||
inv.addItem(config.getIntroBook());
|
||||
inv.addItem(config.getIntroBook(dead));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void determineBookJoin(PlayerJoinEvent event) {
|
||||
if (!config.isEnabled()) return;
|
||||
|
||||
Player alive = event.getPlayer();
|
||||
if (alive == null) return;
|
||||
|
||||
|
||||
UUID puid = alive.getUniqueId();
|
||||
if (puid == null) return;
|
||||
|
||||
|
||||
if (!alive.hasPlayedBefore() || this.hasBook.contains(puid)) {
|
||||
this.hasBook.remove(puid);
|
||||
Inventory inv = alive.getInventory();
|
||||
inv.addItem(config.getIntroBook());
|
||||
inv.addItem(config.getIntroBook(alive));
|
||||
Introbook.bookGiftCount ++;
|
||||
plugin().debug("Gave {0} an introbook", alive.getName());
|
||||
}
|
||||
@@ -149,7 +147,7 @@ public class Introbook extends SimpleHack<IntrobookConfig> implements Listener,
|
||||
sb.append(ChatColor.WHITE).append("\n Introbooks given out: ");
|
||||
sb.append(ChatColor.GREEN).append(Introbook.bookGiftCount);
|
||||
sb.append("\n Current Introbook:");
|
||||
ItemStack book = config.getIntroBook();
|
||||
ItemStack book = config.getIntroBook(null);
|
||||
if (book != null) {
|
||||
BookMeta meta = (BookMeta) book.getItemMeta();
|
||||
if (meta != null) {
|
||||
@@ -169,16 +167,16 @@ public class Introbook extends SimpleHack<IntrobookConfig> implements Listener,
|
||||
sb.append("\n ").append(ChatColor.RED).append("-- in error --");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length < 1) return false;
|
||||
|
||||
|
||||
Player p = plugin().getServer().getPlayer(args[0]);
|
||||
|
||||
|
||||
if (p == null) {
|
||||
try {
|
||||
UUID pu = UUID.fromString(args[0]);
|
||||
@@ -187,16 +185,20 @@ public class Introbook extends SimpleHack<IntrobookConfig> implements Listener,
|
||||
p = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (p == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Unable to find " + args[0]);
|
||||
} else {
|
||||
plugin().log(Level.INFO, "Sent introbook to {0}", args[0]);
|
||||
p.sendMessage(ChatColor.GREEN + "You've been given an introductory book!");
|
||||
Inventory inv = p.getInventory();
|
||||
inv.addItem(config.getIntroBook());
|
||||
inv.addItem(config.getIntroBook(p));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static IntrobookConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new IntrobookConfig(plugin, config);
|
||||
}
|
||||
}
|
||||
+33
-34
@@ -1,45 +1,40 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.InvControlConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import vg.civcraft.mc.namelayer.NameAPI;
|
||||
import net.minecraft.server.v1_10_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_10_R1.NBTTagList;
|
||||
import net.minecraft.server.v1_10_R1.WorldNBTStorage;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.v1_10_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_10_R1.inventory.CraftInventoryPlayer;
|
||||
import org.bukkit.craftbukkit.v1_10_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftInventoryPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.InvControlConfig;
|
||||
import vg.civcraft.mc.namelayer.NameAPI;
|
||||
|
||||
public class InvControl extends SimpleHack<InvControlConfig> implements CommandExecutor, Listener {
|
||||
|
||||
public static final String NAME = "InvControl";
|
||||
|
||||
|
||||
private boolean hasNameAPI;
|
||||
|
||||
|
||||
private Set<UUID> adminsWithInv;
|
||||
|
||||
|
||||
public InvControl(SimpleAdminHacks plugin, InvControlConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
@@ -72,9 +67,10 @@ public class InvControl extends SimpleHack<InvControlConfig> implements CommandE
|
||||
}
|
||||
}
|
||||
if (player == null && playerUID != null) { // Go deep into NBT.
|
||||
WorldNBTStorage storage = (WorldNBTStorage) (((CraftServer) plugin().getServer()).getServer().worlds.get(0).getDataManager());
|
||||
NBTTagCompound rawPlayer = storage.getPlayerData(playerUID.toString());
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
PlayerDataStorage storage = ((CraftServer) plugin().getServer()).getServer().playerDataStorage;
|
||||
CompoundTag rawPlayer = storage.getPlayerData(playerUID.toString());
|
||||
|
||||
if (rawPlayer != null) {
|
||||
plugin().debug("Player {0} found in NBT data, read-only access enabled.", playername);
|
||||
sender.sendMessage("Player found via alternate lookup, read-only access enabled.");
|
||||
@@ -82,16 +78,16 @@ public class InvControl extends SimpleHack<InvControlConfig> implements CommandE
|
||||
sender.sendMessage("Player " + playername + " does not exist or cannot be opened.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
float health = rawPlayer.getFloat("Health");
|
||||
int food = rawPlayer.getInt("foodLevel");
|
||||
|
||||
// Fun NMS inventory reconstruction from file data.
|
||||
net.minecraft.server.v1_10_R1.PlayerInventory nms_pl_inv = new net.minecraft.server.v1_10_R1.PlayerInventory(null);
|
||||
NBTTagList inv = rawPlayer.getList("Inventory", rawPlayer.getTypeId());
|
||||
nms_pl_inv.b(inv); // We use this to bypass the Craft code which requires a player object, unlike NMS.
|
||||
PlayerInventory pl_inv = (PlayerInventory) new CraftInventoryPlayer(nms_pl_inv);
|
||||
|
||||
net.minecraft.world.entity.player.Inventory nms_pl_inv = new net.minecraft.world.entity.player.Inventory(null);
|
||||
ListTag inv = rawPlayer.getList("Inventory", rawPlayer.getId());
|
||||
nms_pl_inv.load(inv); // We use this to bypass the Craft code which requires a player object, unlike NMS.
|
||||
PlayerInventory pl_inv = new CraftInventoryPlayer(nms_pl_inv);
|
||||
|
||||
invSee(sender, pl_inv, health, food, playername);
|
||||
return true;
|
||||
}
|
||||
@@ -111,7 +107,7 @@ public class InvControl extends SimpleHack<InvControlConfig> implements CommandE
|
||||
sender.sendMessage(ChatColor.RED + "Apologies, this is only for in-game operators");
|
||||
} else {
|
||||
Player admin = (Player) sender;
|
||||
|
||||
|
||||
if (admin.equals(player)) {
|
||||
sender.sendMessage(ChatColor.RED + "You cannot modify your own inventory in this manner.");
|
||||
} else {
|
||||
@@ -124,16 +120,16 @@ public class InvControl extends SimpleHack<InvControlConfig> implements CommandE
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void adminCloseInventory(InventoryCloseEvent event) {
|
||||
if (event.getPlayer() != null && this.adminsWithInv.contains(event.getPlayer().getUniqueId())) {
|
||||
if (this.adminsWithInv.contains(event.getPlayer().getUniqueId())) {
|
||||
this.adminsWithInv.remove(event.getPlayer().getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void invSee(CommandSender sender, PlayerInventory pl_inv, double health, int food, String playername) {
|
||||
if (!(sender instanceof Player)) { // send text only.
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(playername).append("'s\n Health: ").append((int)health*2);
|
||||
sb.append("\n Food: ").append(food);
|
||||
sb.append("\n Inventory: ");
|
||||
@@ -144,7 +140,7 @@ public class InvControl extends SimpleHack<InvControlConfig> implements CommandE
|
||||
sb.append("\n Feet: ").append(pl_inv.getBoots());
|
||||
for (int slot = 0; slot < 36; slot++) {
|
||||
final ItemStack it = pl_inv.getItem(slot);
|
||||
sb.append("\n ").append(slot).append(":").append(it);
|
||||
sb.append("\n ").append(slot).append(":").append(it).append(ChatColor.RESET);
|
||||
}
|
||||
sender.sendMessage(sb.toString());
|
||||
} else {
|
||||
@@ -177,7 +173,7 @@ public class InvControl extends SimpleHack<InvControlConfig> implements CommandE
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,4 +218,7 @@ public class InvControl extends SimpleHack<InvControlConfig> implements CommandE
|
||||
}
|
||||
}
|
||||
|
||||
public static InvControlConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new InvControlConfig(plugin, config);
|
||||
}
|
||||
}
|
||||
+102
-28
@@ -1,12 +1,17 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.NewfriendAssistConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.BroadcastLevel;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -14,14 +19,9 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.BroadcastLevel;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.NewfriendAssistConfig;
|
||||
|
||||
/**
|
||||
* A simple Newfriend tracker and assist module. Keeps track of newfriends so far.
|
||||
@@ -29,7 +29,7 @@ import com.programmerdan.minecraft.simpleadminhacks.configs.NewfriendAssistConfi
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implements Listener, CommandExecutor {
|
||||
|
||||
|
||||
public static final String NAME = "NewfriendAssist";
|
||||
private static long newfriendCount = 0l;
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
* Track standard quit events to monitor newfriend playtime on the day of join.
|
||||
*/
|
||||
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true)
|
||||
public void NewLeaveEvent(PlayerQuitEvent exit) {
|
||||
public void newLeaveEvent(PlayerQuitEvent exit) {
|
||||
if (!config.isEnabled()) return;
|
||||
doLeave(exit.getPlayer());
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
* Track standard kick events to monitor newfriend playtime on the day of join.
|
||||
*/
|
||||
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true)
|
||||
public void NewKickEvent(PlayerKickEvent exit) {
|
||||
public void newKickEvent(PlayerKickEvent exit) {
|
||||
if (!config.isEnabled()) return;
|
||||
doLeave(exit.getPlayer());
|
||||
}
|
||||
@@ -93,11 +93,11 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
|
||||
newfriendNames.put(newUUID, newfriend.getName());
|
||||
newfriendSessionTime.put(newUUID, new SessionTime(System.currentTimeMillis()));
|
||||
|
||||
if (config.getAnnounceBroadcast().size() > 0) {
|
||||
|
||||
if (!config.getAnnounceBroadcast().isEmpty()) {
|
||||
// Prepare message
|
||||
String cleanMessage = cleanMessage(join);
|
||||
|
||||
|
||||
// Overlap is possible. Some people might get double-notified
|
||||
for (BroadcastLevel level : config.getAnnounceBroadcast()) {
|
||||
plugin().debug(" Broadcast to {0}", level);
|
||||
@@ -117,7 +117,7 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (config.isIntroKitEnabled()) {
|
||||
ItemStack[] introKit = config.getIntroKit();
|
||||
if (introKit != null && introKit.length > 0) {
|
||||
@@ -126,9 +126,40 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
plugin().log(Level.INFO, " Gave newbit kit to {0}", newfriend.getDisplayName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expanding the usage of this class to allow us to give RandomSpawning players a kit on each respawn.
|
||||
* This method checks if the respawn event is a bed or anchor respawn and if not, gives them the introkit.
|
||||
* @param event PlayerRespawnEvent
|
||||
*/
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onRespawn(PlayerRespawnEvent event) {
|
||||
if (!config.giveToRandomSpawners()) {
|
||||
return;
|
||||
}
|
||||
if (event.isAnchorSpawn()) {
|
||||
return;
|
||||
}
|
||||
if (event.isBedSpawn()) {
|
||||
return;
|
||||
}
|
||||
//Checking here if the player hasn't played before so we don't double spawn a starter kit
|
||||
if (!event.getPlayer().hasPlayedBefore()) {
|
||||
return;
|
||||
}
|
||||
if (config.isIntroKitEnabled()) {
|
||||
ItemStack[] introKit = config.getIntroKit();
|
||||
if (introKit != null && introKit.length > 0) {
|
||||
Inventory inv = event.getPlayer().getInventory();
|
||||
inv.addItem(introKit);
|
||||
plugin().log(Level.INFO, " Gave randomspawner kit to {0}", event.getPlayer().getDisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String cleanMessage(PlayerJoinEvent event) {
|
||||
return ChatColor.translateAlternateColorCodes('&',
|
||||
config.getAnnounceMessage()
|
||||
@@ -154,8 +185,8 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
this.newfriendNames = new HashMap<UUID, String>();
|
||||
this.newfriendSessionTime = new HashMap<UUID, SessionTime>();
|
||||
this.newfriendNames = new HashMap<>();
|
||||
this.newfriendSessionTime = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,7 +215,7 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
*/
|
||||
@Override
|
||||
public String status() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (config != null && config.isEnabled()) {
|
||||
sb.append("NewfriendAssist.PlayerJoin/Quit/KickEvent monitoring active");
|
||||
} else {
|
||||
@@ -193,7 +224,7 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
|
||||
sb.append("\n Since server start, ").append(NewfriendAssist.newfriendCount)
|
||||
.append(" new players have joined.");
|
||||
|
||||
|
||||
if (this.newfriendNames != null && !this.newfriendNames.isEmpty()) {
|
||||
sb.append("\n New players since this hack was last enabled:");
|
||||
for (HashMap.Entry<UUID, String> entry : this.newfriendNames.entrySet()) {
|
||||
@@ -204,7 +235,7 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (config.isIntroKitEnabled()) {
|
||||
sb.append("\n Introkit gifting is enabled. Current Introkit:");
|
||||
if (config.getIntroKit() != null && config.getIntroKit().length > 0 ) {
|
||||
@@ -220,18 +251,18 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!config.isIntroKitEnabled()) {
|
||||
sender.sendMessage(ChatColor.RED + "Introkit gifting is disabled.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (args.length < 1) return false;
|
||||
|
||||
|
||||
Player p = plugin().getServer().getPlayer(args[0]);
|
||||
|
||||
|
||||
if (p == null) {
|
||||
try {
|
||||
UUID pu = UUID.fromString(args[0]);
|
||||
@@ -240,7 +271,7 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
p = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (p == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Unable to find " + args[0]);
|
||||
} else {
|
||||
@@ -249,8 +280,51 @@ public class NewfriendAssist extends SimpleHack<NewfriendAssistConfig> implement
|
||||
Inventory inv = p.getInventory();
|
||||
inv.addItem(config.getIntroKit());
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static NewfriendAssistConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new NewfriendAssistConfig(plugin, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple data storage and processing class for NewfriendAssist and elsewhere to track playtime.
|
||||
*
|
||||
* @author ProgrammerDan programmerdan@gmail.com
|
||||
*/
|
||||
public static class SessionTime {
|
||||
private long playtimeTotal;
|
||||
private long lastJoin;
|
||||
|
||||
public SessionTime(long joinTime) {
|
||||
playtimeTotal = 0l;
|
||||
lastJoin = joinTime;
|
||||
}
|
||||
|
||||
public long endSession(long leaveTime) {
|
||||
if (lastJoin > 0l) {
|
||||
playtimeTotal = leaveTime - lastJoin;
|
||||
lastJoin = 0;
|
||||
}
|
||||
|
||||
return playtimeTotal;
|
||||
}
|
||||
|
||||
public void startSession(long startTime) {
|
||||
if (lastJoin > 0l) {
|
||||
endSession(startTime);
|
||||
}
|
||||
lastJoin = startTime;
|
||||
}
|
||||
|
||||
public long totalTime() {
|
||||
long toReturn = playtimeTotal;
|
||||
if (lastJoin > 0l && System.currentTimeMillis() > lastJoin) {
|
||||
toReturn += System.currentTimeMillis() - lastJoin;
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.ReinforcedChestBreakConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import vg.civcraft.mc.citadel.Citadel;
|
||||
import vg.civcraft.mc.citadel.ReinforcementManager;
|
||||
|
||||
/**
|
||||
* Sends every 3 minutes a message to the admins if a chest is broken
|
||||
*/
|
||||
public class ReinforcedChestBreak extends SimpleHack<ReinforcedChestBreakConfig> implements Listener {
|
||||
|
||||
public static String NAME = "ReinforcedChestBreak";
|
||||
|
||||
private ReinforcementManager manager;
|
||||
private Messenger messenger;
|
||||
private Set<String> messages;
|
||||
|
||||
public ReinforcedChestBreak(SimpleAdminHacks plugin, ReinforcedChestBreakConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
public static ReinforcedChestBreakConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new ReinforcedChestBreakConfig(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (!config.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
if (!config.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
messages = new HashSet<>();
|
||||
|
||||
manager = Citadel.getInstance().getReinforcementManager();
|
||||
messenger = new Messenger();
|
||||
|
||||
Bukkit.getScheduler().runTaskTimer(plugin(), messenger, 0, config.getDelay() * 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
return "Delay: " + config.getDelay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets fired by the BLockBreakEvent and checks if the block is reinforced
|
||||
* @param eve BLockBreakEvent
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true)
|
||||
public void onBlockBreak(BlockBreakEvent eve) {
|
||||
if (!config.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
Material bbe = eve.getBlock().getType();
|
||||
if (manager == null) {
|
||||
manager = Citadel.getInstance().getReinforcementManager();
|
||||
}
|
||||
// the list of items with inventories has grown a bit (1.14)
|
||||
if (Material.CHEST.equals(bbe) || Material.TRAPPED_CHEST.equals(bbe)
|
||||
|| Material.ENDER_CHEST.equals(bbe) || Material.FURNACE.equals(bbe)
|
||||
|| Material.BLAST_FURNACE.equals(bbe) || Material.DISPENSER.equals(bbe)
|
||||
|| Material.DROPPER.equals(bbe) || Material.HOPPER.equals(bbe)
|
||||
|| Material.BARREL.equals(bbe) || Material.SMOKER.equals(bbe)
|
||||
|| Material.BLACK_SHULKER_BOX.equals(bbe)
|
||||
|| Material.BLUE_SHULKER_BOX.equals(bbe)
|
||||
|| Material.BROWN_SHULKER_BOX.equals(bbe)
|
||||
|| Material.CYAN_SHULKER_BOX.equals(bbe)
|
||||
|| Material.GRAY_SHULKER_BOX.equals(bbe)
|
||||
|| Material.GREEN_SHULKER_BOX.equals(bbe)
|
||||
|| Material.LIGHT_BLUE_SHULKER_BOX.equals(bbe)
|
||||
|| Material.LIGHT_GRAY_SHULKER_BOX.equals(bbe)
|
||||
|| Material.LIME_SHULKER_BOX.equals(bbe)
|
||||
|| Material.MAGENTA_SHULKER_BOX.equals(bbe)
|
||||
|| Material.ORANGE_SHULKER_BOX.equals(bbe)
|
||||
|| Material.PINK_SHULKER_BOX.equals(bbe)
|
||||
|| Material.PURPLE_SHULKER_BOX.equals(bbe)
|
||||
|| Material.RED_SHULKER_BOX.equals(bbe)
|
||||
|| Material.SHULKER_BOX.equals(bbe)
|
||||
|| Material.WHITE_SHULKER_BOX.equals(bbe)
|
||||
|| Material.YELLOW_SHULKER_BOX.equals(bbe)
|
||||
|| Material.LECTERN.equals(bbe) || Material.BREWING_STAND.equals(bbe)) {
|
||||
if(manager.getReinforcement(eve.getBlock()) != null) {
|
||||
String name = eve.getPlayer().getDisplayName();
|
||||
Location loc = eve.getBlock().getLocation();
|
||||
|
||||
String msg = setVars(name,
|
||||
String.valueOf(loc.getBlockX()),
|
||||
String.valueOf(loc.getBlockY()),
|
||||
String.valueOf(loc.getBlockZ()));
|
||||
|
||||
if(messages.add(msg)) {
|
||||
plugin().log(Level.INFO, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the message
|
||||
* @param name the player name
|
||||
* @param x block x
|
||||
* @param y block y
|
||||
* @param z block z
|
||||
* @return returns the builded String
|
||||
*/
|
||||
private String setVars(String name, String x, String y, String z) {
|
||||
return ChatColor.translateAlternateColorCodes('&', config.getMessage()
|
||||
.replace("%player%", name)
|
||||
.replace("%x%", x)
|
||||
.replace("%y%", y)
|
||||
.replace("%z%", z));
|
||||
}
|
||||
|
||||
private class Messenger implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (String message: messages) {
|
||||
plugin().serverOperatorBroadcast(message);
|
||||
}
|
||||
messages.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.SanityHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
|
||||
public class SanityHack extends SimpleHack<SanityHackConfig> implements Listener {
|
||||
|
||||
public static final String NAME = "SanityHack";
|
||||
|
||||
private final int trackingLevel;
|
||||
private int caughtPlayers; // Just to give a useful message in status tbh
|
||||
|
||||
public SanityHack(SimpleAdminHacks plugin, SanityHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.trackingLevel = config.getTrackingLevel();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled=true)
|
||||
public void onBlockBreak(BlockBreakEvent event){
|
||||
if(!config.isEnabled()) return;
|
||||
if(!config.isTrackingBreak()) return;
|
||||
|
||||
|
||||
Block block = event.getBlock();
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (player == null) return;
|
||||
if (block == null) return;
|
||||
|
||||
if(block.getY() < trackingLevel){
|
||||
plugin().log(Level.INFO, "Player({0}, {1}) caught breaking a block({2}) below Y {3} at {4}", player.getName(), player.getUniqueId().toString(),
|
||||
block.getType().toString(), trackingLevel, block.getLocation());
|
||||
caughtPlayers++;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled=true)
|
||||
public void onBlockPlace(BlockPlaceEvent event){
|
||||
if(!config.isEnabled()) return;
|
||||
if(!config.isTrackingPlace()) return;
|
||||
|
||||
Block block = event.getBlock();
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (player == null) return;
|
||||
if (block == null) return;
|
||||
|
||||
if(block.getY() < trackingLevel && player != null){
|
||||
plugin().log(Level.INFO, "Player({0}, {1}) caught placing a block({2}) below Y {3} at {4}", player.getName(), player.getUniqueId().toString(),
|
||||
block.getType().toString(), trackingLevel, block.getLocation());
|
||||
caughtPlayers++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering SanityHack listeners");
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
caughtPlayers = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
caughtPlayers = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
if (!config.isEnabled()) {
|
||||
return "Sanity Hack listening disabled.";
|
||||
}
|
||||
|
||||
return caughtPlayers + " caught below Y " + trackingLevel;
|
||||
}
|
||||
|
||||
public static SanityHackConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new SanityHackConfig(plugin, config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1090
File diff suppressed because it is too large.
Load diff
+140
@@ -0,0 +1,140 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.ToggleLampConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.Lightable;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import vg.civcraft.mc.citadel.Citadel;
|
||||
import vg.civcraft.mc.citadel.ReinforcementManager;
|
||||
import vg.civcraft.mc.citadel.model.Reinforcement;
|
||||
|
||||
public class ToggleLamp extends SimpleHack<ToggleLampConfig> implements Listener {
|
||||
|
||||
public static final String NAME = "ToggleLamp";
|
||||
|
||||
private static final String META_COOLDOWN = "ToggleLamp_NextToggle";
|
||||
private static final String META_TOGGLED = "ToggleLamp_Toggled";
|
||||
|
||||
private ReinforcementManager rm;
|
||||
|
||||
public ToggleLamp(SimpleAdminHacks plugin, ToggleLampConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
if (!config.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
Block clickedBlock = event.getClickedBlock();
|
||||
if (clickedBlock == null) {
|
||||
return;
|
||||
}
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
if (event.getItem() == null) {
|
||||
return;
|
||||
}
|
||||
if (event.getHand() != EquipmentSlot.HAND || event.getItem().getType() != Material.STICK) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player eventPlayer = event.getPlayer();
|
||||
Material clickedBlockMat = clickedBlock.getType();
|
||||
|
||||
if (clickedBlockMat != Material.REDSTONE_LAMP) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean toggled = clickedBlock.hasMetadata(META_TOGGLED)
|
||||
&& clickedBlock.getMetadata(META_TOGGLED).get(0).asBoolean();
|
||||
|
||||
if (clickedBlock.hasMetadata(META_COOLDOWN)) {
|
||||
MetadataValue val = clickedBlock.getMetadata(META_COOLDOWN).get(0);
|
||||
if (((long) val.value()) > System.currentTimeMillis()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rm != null) {
|
||||
Reinforcement rein = rm.getReinforcement(clickedBlock);
|
||||
if (rein != null) {
|
||||
if (!rein.getGroup().isMember(eventPlayer.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
switchLamp(clickedBlock, !toggled);
|
||||
eventPlayer.getWorld().playSound(clickedBlock.getLocation(), Sound.BLOCK_LEVER_CLICK, 0.5F, 1.0F);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (config.isEnabled()) {
|
||||
plugin().log("Registering ToggleLamp listeners");
|
||||
plugin().registerListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataBootstrap() {
|
||||
rm = plugin().serverHasPlugin("Citadel") ? Citadel.getInstance().getReinforcementManager() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCommands() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataCleanup() {
|
||||
rm = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String status() {
|
||||
return config.isEnabled() ? "ToggleLamp enabled." : "ToggleLamp disabled.";
|
||||
}
|
||||
|
||||
public static ToggleLampConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) {
|
||||
return new ToggleLampConfig(plugin, config);
|
||||
}
|
||||
|
||||
private void switchLamp(Block block, boolean lit) {
|
||||
|
||||
if (block.getType() != Material.REDSTONE_LAMP) {
|
||||
return;
|
||||
}
|
||||
|
||||
Lightable lightable = (Lightable) block.getBlockData();
|
||||
lightable.setLit(lit);
|
||||
block.setBlockData(lightable);
|
||||
|
||||
block.setMetadata(META_TOGGLED, new FixedMetadataValue(plugin(), lit));
|
||||
block.setMetadata(META_COOLDOWN,
|
||||
new FixedMetadataValue(plugin(), System.currentTimeMillis() + config.getCooldownTime()));
|
||||
}
|
||||
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.PacketManager;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.MaterialUtils;
|
||||
import vg.civcraft.mc.civmodcore.utilities.TextUtil;
|
||||
import vg.civcraft.mc.civmodcore.utilities.cooldowns.ICoolDownHandler;
|
||||
import vg.civcraft.mc.civmodcore.utilities.cooldowns.MilliSecCoolDownHandler;
|
||||
import vg.civcraft.mc.civmodcore.utilities.ratelimiting.RateLimiter;
|
||||
import vg.civcraft.mc.civmodcore.utilities.ratelimiting.RateLimiting;
|
||||
|
||||
/**
|
||||
* Prevents "CivBreak" by denying continuous block break packets.
|
||||
*/
|
||||
public final class AntiFastBreak extends BasicHack {
|
||||
|
||||
private final PacketManager packets;
|
||||
private final Map<UUID, Map<Location, Long>> miningLocations;
|
||||
private final RateLimiter violationLimiter;
|
||||
private final RateLimiter loggerLimiter;
|
||||
private ICoolDownHandler<UUID> punishCooldown;
|
||||
|
||||
@AutoLoad(id = "laggLenciency") // Continue to support typo
|
||||
private double lagLeniency;
|
||||
|
||||
@AutoLoad
|
||||
private long breakDenyDuration;
|
||||
|
||||
public AntiFastBreak(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.packets = new PacketManager();
|
||||
this.miningLocations = new TreeMap<>();
|
||||
this.violationLimiter = RateLimiting.createRateLimiter("antiCivBreak", 10, 10, 1, 2_000L);
|
||||
this.loggerLimiter = RateLimiting.createRateLimiter("antiCivBreakLogger", 4, 4, 1, 10_000L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
if (this.breakDenyDuration <= 0) {
|
||||
this.breakDenyDuration = 3000;
|
||||
plugin().warning("Invalid break deny duration, defaulting to 3000ms");
|
||||
}
|
||||
this.punishCooldown = new MilliSecCoolDownHandler<>(this.breakDenyDuration);
|
||||
this.packets.addAdapter(new PacketAdapter(plugin(), PacketType.Play.Client.BLOCK_DIG) {
|
||||
@Override
|
||||
public void onPacketReceiving(final PacketEvent event) {
|
||||
final PacketContainer packet = event.getPacket();
|
||||
final Player player = event.getPlayer();
|
||||
final BlockPosition position = packet.getBlockPositionModifier().read(0);
|
||||
final Location location = position.toLocation(player.getWorld());
|
||||
switch (packet.getPlayerDigTypes().read(0)) {
|
||||
case START_DESTROY_BLOCK:
|
||||
handleStartDigging(player, location);
|
||||
return;
|
||||
case STOP_DESTROY_BLOCK:
|
||||
handleFinishingDigging(player, location);
|
||||
return;
|
||||
default:
|
||||
// some other stuff we dont care about
|
||||
//return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.packets.removeAllAdapters();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(final PlayerQuitEvent event) {
|
||||
this.miningLocations.remove(event.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onBlockBreak(final BlockBreakEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (!this.punishCooldown.onCoolDown(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
player.sendMessage(ChatColor.RED + "Denying break due to abnormal break speed");
|
||||
plugin().debug("Denying block break for " + player.getName() + " due cooldown for another "
|
||||
+ TextUtil.formatDuration(this.punishCooldown.getRemainingCoolDown(player.getUniqueId())));
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
private void handleStartDigging(final Player player, final Location location) {
|
||||
this.miningLocations
|
||||
.computeIfAbsent(player.getUniqueId(), uuid -> new HashMap<>())
|
||||
.putIfAbsent(location, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private void reward(final Player player) {
|
||||
this.violationLimiter.addTokens(player.getUniqueId(), 1);
|
||||
}
|
||||
|
||||
private void handleFinishingDigging(final Player player, final Location location) {
|
||||
final Map<Location, Long> miningLocs = this.miningLocations
|
||||
.computeIfAbsent(player.getUniqueId(), uuid -> new HashMap<>());
|
||||
final int ticksToBreak = getTicksToBreak(location.getBlock(), player);
|
||||
final Long timeStarted = miningLocs.remove(location);
|
||||
if (timeStarted == null) {
|
||||
if (ticksToBreak > 1) {
|
||||
plugin().debug(player.getName() + " tried to instabreak non-instabreakable block");
|
||||
punish(player);
|
||||
}
|
||||
else {
|
||||
reward(player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ticksToBreak == 0) {
|
||||
plugin().debug(player.getName() + " instabroke allowed block " + location.getBlock());
|
||||
reward(player);
|
||||
return;
|
||||
}
|
||||
final long msToBreak = ticksToBreak * 50L;
|
||||
final long now = System.currentTimeMillis();
|
||||
final long timePassed = now - timeStarted;
|
||||
//plugin().debug("Measured " + timePassed + " for allowed time of " + TextUtil.formatDuration(msToBreak));
|
||||
miningLocs.put(location, now);
|
||||
if ((timePassed * this.lagLeniency) < msToBreak) {
|
||||
punish(player);
|
||||
}
|
||||
else {
|
||||
reward(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void punish(final Player player) {
|
||||
plugin().debug("Attempting to decrement token count for " + player.getName());
|
||||
if (!this.violationLimiter.pullToken(player)) {
|
||||
plugin().debug("Could not decrement token count for " + player.getName() + ", punishing...");
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin(), () -> {
|
||||
this.punishCooldown.putOnCoolDown(player.getUniqueId());
|
||||
if (this.loggerLimiter.pullToken(player.getUniqueId()) || plugin().isDebugEnabled()) {
|
||||
plugin().warning(player.getName() + " is possibly using civ break, fast break detected");
|
||||
}
|
||||
player.sendMessage(ChatColor.RED + "You are breaking blocks too fast");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static float getDamagePerTick(final Material material, final Player player) {
|
||||
final ItemStack tool = player.getInventory().getItemInMainHand();
|
||||
final BlockState blockData = getNMSBlockData(material);
|
||||
if (blockData == null) {
|
||||
throw new IllegalArgumentException("Could not determine block break type for " + material);
|
||||
}
|
||||
// if you ever need to version upgrade this, search for a method in n.m.s.Item
|
||||
// calling "getDestroySpeed(this,blockData)" in n.m.s.ItemStack
|
||||
float damagePerTick = CraftItemStack.asNMSCopy(tool).getDestroySpeed(blockData);
|
||||
// above method does not include efficiency or haste, so we add it ourselves
|
||||
final int effLevel = tool.getEnchantmentLevel(Enchantment.DIG_SPEED);
|
||||
int efficiencyBonus = 0;
|
||||
if (effLevel > 0 && damagePerTick > 1.0) { //damage per tick greater than 1.0 signals proper tool
|
||||
efficiencyBonus = effLevel * effLevel + 1;
|
||||
}
|
||||
damagePerTick += efficiencyBonus;
|
||||
int hasteLevel = 0;
|
||||
final PotionEffect hasteEffect = player.getPotionEffect(PotionEffectType.FAST_DIGGING);
|
||||
if (hasteEffect != null) {
|
||||
// amplifier of 0 is potion effect at level one
|
||||
hasteLevel = hasteEffect.getAmplifier() + 1;
|
||||
}
|
||||
damagePerTick *= 1.0 + 0.2 * hasteLevel;
|
||||
return damagePerTick;
|
||||
}
|
||||
|
||||
private static int getTicksToBreak(final Block block, final Player player) {
|
||||
final Material material = block.getType();
|
||||
if (!material.isBlock() || MaterialUtils.isAir(material)) {
|
||||
// lagg, player is breaking a block already gone
|
||||
return 0;
|
||||
}
|
||||
final float damageToDeal = material.getHardness() * 30;
|
||||
final float damagePerTick = getDamagePerTick(material, player);
|
||||
if (damageToDeal <= damagePerTick) {
|
||||
// instabreak
|
||||
return 0;
|
||||
}
|
||||
return (int) Math.ceil(damageToDeal / damagePerTick);
|
||||
}
|
||||
|
||||
private static BlockState getNMSBlockData(final Material material) {
|
||||
final net.minecraft.world.level.block.Block nmsBlock = CraftMagicNumbers.getBlock(material);
|
||||
if (nmsBlock == null) {
|
||||
return null;
|
||||
}
|
||||
return nmsBlock.defaultBlockState();
|
||||
}
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.EnderPearl;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import vg.civcraft.mc.civmodcore.config.ConfigHelper;
|
||||
|
||||
public class AntiStatisChamber extends BasicHack {
|
||||
|
||||
@AutoLoad
|
||||
private String pearlLifetime;
|
||||
private long lifetimeValue;
|
||||
private NamespacedKey key;
|
||||
|
||||
public AntiStatisChamber(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.key = new NamespacedKey(plugin, "pearl_thrown_time");
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerThrowPearl(PlayerLaunchProjectileEvent event) {
|
||||
Projectile projectile = event.getProjectile();
|
||||
if (!(projectile instanceof EnderPearl)) {
|
||||
return;
|
||||
}
|
||||
EnderPearl pearl = (EnderPearl) projectile;
|
||||
PersistentDataContainer pdc = pearl.getPersistentDataContainer();
|
||||
pdc.set(key, PersistentDataType.LONG, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPearlLand(ProjectileHitEvent event) {
|
||||
this.lifetimeValue = ConfigHelper.parseTime(this.pearlLifetime);
|
||||
Projectile projectile = event.getEntity();
|
||||
if (!(projectile instanceof EnderPearl)) {
|
||||
return;
|
||||
}
|
||||
EnderPearl pearl = (EnderPearl) projectile;
|
||||
PersistentDataContainer pdc = pearl.getPersistentDataContainer();
|
||||
Long pearlThrownTime = pdc.get(key, PersistentDataType.LONG);
|
||||
if (pearlThrownTime == null) {
|
||||
pearl.remove();
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if ((System.currentTimeMillis() - pearlThrownTime) > lifetimeValue) {
|
||||
//We remove the pearl here because cancelling the event doesn't prevent the pearl from actually landing
|
||||
pearl.remove();
|
||||
if (pearl.getShooter() instanceof Player) {
|
||||
((Player) pearl.getShooter()).sendMessage(Component.text("Your pearl failed to land for being in flight for more than " + pearlLifetime).color(NamedTextColor.RED));
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.MetaUtils;
|
||||
|
||||
public class ArmourBound extends BasicHack {
|
||||
|
||||
private SimpleAdminHacks plugin;
|
||||
private NamespacedKey key;
|
||||
@AutoLoad
|
||||
private List<String> whitelist;
|
||||
|
||||
public ArmourBound(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.plugin = plugin;
|
||||
this.key = new NamespacedKey(plugin, "SAH_ArmourBound");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onArmourEquip(PlayerArmorChangeEvent event){
|
||||
Player player = event.getPlayer();
|
||||
ItemStack newItem = event.getNewItem();
|
||||
if (newItem == null) {
|
||||
return;
|
||||
}
|
||||
if (newItem.getType() == Material.AIR) {
|
||||
return;
|
||||
}
|
||||
EquipmentSlot realSlot = getRealSlot(event.getSlotType());
|
||||
if (realSlot == null) {
|
||||
return;
|
||||
}
|
||||
//From here, we take over from the copy, get the actual itemstack ourselves
|
||||
newItem = player.getInventory().getItem(realSlot);
|
||||
if (!whitelist.contains(newItem.getType().toString())) {
|
||||
return;
|
||||
}
|
||||
ItemMeta meta = newItem.getItemMeta();
|
||||
PersistentDataContainer itemContainer = meta.getPersistentDataContainer();
|
||||
if (itemContainer.get(this.key, PersistentDataType.STRING) == null) {
|
||||
itemContainer.set(this.key, PersistentDataType.STRING, player.getUniqueId().toString());
|
||||
Component boundComponent = Component.text("This armor is bound to: ").decoration(TextDecoration.ITALIC, false).color(NamedTextColor.WHITE).append(Component.text(player.getName()).color(NamedTextColor.GOLD));
|
||||
MetaUtils.addComponentLore(meta, boundComponent);
|
||||
newItem.setItemMeta(meta);
|
||||
return;
|
||||
}
|
||||
UUID boundUUID = UUID.fromString(itemContainer.get(this.key, PersistentDataType.STRING));
|
||||
if (!boundUUID.equals(player.getUniqueId())) {
|
||||
player.closeInventory();
|
||||
ItemStack toDrop = newItem.clone();
|
||||
newItem.setAmount(0);
|
||||
player.getWorld().dropItemNaturally(player.getLocation(), toDrop);
|
||||
player.sendMessage(Component.text("This armor is not bound to you!").color(NamedTextColor.RED));
|
||||
}
|
||||
}
|
||||
|
||||
private EquipmentSlot getRealSlot(PlayerArmorChangeEvent.SlotType slotType) {
|
||||
switch (slotType) {
|
||||
case HEAD:
|
||||
return EquipmentSlot.HEAD;
|
||||
case CHEST:
|
||||
return EquipmentSlot.CHEST;
|
||||
case LEGS:
|
||||
return EquipmentSlot.LEGS;
|
||||
case FEET:
|
||||
return EquipmentSlot.FEET;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.SpawnEggUtils;
|
||||
|
||||
public class ArthropodEggHack extends BasicHack {
|
||||
|
||||
@AutoLoad
|
||||
private double eggChance;
|
||||
|
||||
@AutoLoad
|
||||
private double lootingChance;
|
||||
|
||||
@AutoLoad
|
||||
private boolean removeDrops;
|
||||
|
||||
@AutoLoad
|
||||
private List<String> allowedTypes;
|
||||
|
||||
public ArthropodEggHack(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityDeath(EntityDeathEvent event) {
|
||||
Player targetPlayer = event.getEntity().getKiller();
|
||||
if (null == targetPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
String type = event.getEntity().getType().toString();
|
||||
if (allowedTypes == null || !allowedTypes.contains(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for a baby animal
|
||||
if (event.getEntity() instanceof Ageable) {
|
||||
Ageable ageableEntity = (Ageable) event.getEntity();
|
||||
if (!ageableEntity.isAdult()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the player's currently equipped weapon
|
||||
ItemStack handstack = targetPlayer.getEquipment().getItemInMainHand();
|
||||
// Get the map of enchantments on that item
|
||||
Map<Enchantment, Integer> itemEnchants = handstack.getEnchantments();
|
||||
if (itemEnchants.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if one enchantment is BaneOfArthropods
|
||||
if (null == itemEnchants.get(Enchantment.DAMAGE_ARTHROPODS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
double randomNum = Math.random();
|
||||
double levelOfArthropod = handstack.getEnchantmentLevel(Enchantment.DAMAGE_ARTHROPODS);
|
||||
double levelOfLooting = handstack.getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS);
|
||||
|
||||
double targetPercentage = (eggChance * levelOfArthropod) + (lootingChance * levelOfLooting);
|
||||
|
||||
// Check if egg should be spawned
|
||||
if (randomNum < targetPercentage) {
|
||||
ItemStack item = new ItemStack(SpawnEggUtils.getSpawnEgg(event.getEntityType()), 1);
|
||||
if (removeDrops) {
|
||||
event.getDrops().clear();
|
||||
event.setDroppedExp(0);
|
||||
}
|
||||
event.getDrops().add(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.Pair;
|
||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||
import com.destroystokyo.paper.MaterialTags;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.PacketManager;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.Damageable;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.LeatherArmorMeta;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.potion.PotionData;
|
||||
|
||||
public final class AttrHider extends BasicHack {
|
||||
|
||||
public static final String BYPASS_PERMISSION = "attrhider.bypass";
|
||||
|
||||
private final PacketManager packets = new PacketManager();
|
||||
|
||||
@AutoLoad
|
||||
private boolean hideItemMeta;
|
||||
|
||||
@AutoLoad
|
||||
private boolean hideEffects;
|
||||
|
||||
@AutoLoad
|
||||
private boolean hideHealth;
|
||||
|
||||
public AttrHider(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
if (!this.hideItemMeta) {
|
||||
this.packets.addAdapter(new PacketAdapter(this.plugin, PacketType.Play.Server.ENTITY_EQUIPMENT) {
|
||||
@Override
|
||||
public void onPacketSending(final PacketEvent event) {
|
||||
final PacketContainer packet = event.getPacket();
|
||||
if (event.getPlayer().hasPermission(BYPASS_PERMISSION)) {
|
||||
return;
|
||||
}
|
||||
final var slots = packet.getSlotStackPairLists();
|
||||
final var slotItemPairs = slots.read(0);
|
||||
for (final Pair<EnumWrappers.ItemSlot, ItemStack> slotItemPair : slotItemPairs) {
|
||||
final ItemStack item = slotItemPair.getSecond();
|
||||
if (item == null || !shouldBeObfuscated(item.getType())) {
|
||||
continue;
|
||||
}
|
||||
final ItemMeta meta = item.getItemMeta();
|
||||
final ItemStack fakeItem = item.clone();
|
||||
if (meta != null) {
|
||||
final ItemMeta fakeMeta = fakeItem.getItemMeta();
|
||||
if (meta instanceof LeatherArmorMeta) {
|
||||
final LeatherArmorMeta baseLeatherMeta = (LeatherArmorMeta) meta;
|
||||
final LeatherArmorMeta fakeLeatherMeta = (LeatherArmorMeta) fakeMeta;
|
||||
fakeLeatherMeta.setColor(baseLeatherMeta.getColor());
|
||||
}
|
||||
if (meta instanceof PotionMeta) {
|
||||
final PotionMeta basePotionMeta = (PotionMeta) meta;
|
||||
final PotionMeta fakePotionMeta = (PotionMeta) fakeMeta;
|
||||
final PotionData basePotion = basePotionMeta.getBasePotionData();
|
||||
final PotionData fakePotion = new PotionData(basePotion.getType());
|
||||
fakePotionMeta.setBasePotionData(fakePotion);
|
||||
}
|
||||
if (meta instanceof Damageable) {
|
||||
final Damageable fakeDamageable = (Damageable) fakeMeta;
|
||||
fakeDamageable.setDamage(0);
|
||||
}
|
||||
if (meta.hasEnchants()) {
|
||||
for (Enchantment enchantment : fakeMeta.getEnchants().keySet()) {
|
||||
fakeMeta.removeEnchant(enchantment);
|
||||
}
|
||||
fakeMeta.addEnchant(Enchantment.DURABILITY, 1, true);
|
||||
}
|
||||
fakeItem.setItemMeta(fakeMeta);
|
||||
slotItemPair.setSecond(fakeItem); // Set item
|
||||
}
|
||||
}
|
||||
slots.write(0, slotItemPairs);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.hideEffects) {
|
||||
this.packets.addAdapter(new PacketAdapter(this.plugin, PacketType.Play.Server.ENTITY_EFFECT) {
|
||||
@Override
|
||||
public void onPacketSending(final PacketEvent event) {
|
||||
final PacketContainer packet = event.getPacket();
|
||||
final Player player = event.getPlayer();
|
||||
if (player.hasPermission(BYPASS_PERMISSION)) {
|
||||
return;
|
||||
}
|
||||
final PacketContainer cloned = packet.deepClone();
|
||||
final StructureModifier<Integer> ints = cloned.getIntegers();
|
||||
if (player.getEntityId() == ints.read(0)) {
|
||||
return;
|
||||
}
|
||||
// set amplifier to 0
|
||||
cloned.getBytes().write(1, (byte) 0);
|
||||
// set duration to 0
|
||||
ints.write(1, 0);
|
||||
// The packet data is shared between events, but the event
|
||||
// instance is exclusive to THIS sending of the packet
|
||||
event.setPacket(cloned);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.hideHealth) {
|
||||
this.packets.addAdapter(new PacketAdapter(this.plugin, PacketType.Play.Server.ENTITY_METADATA) {
|
||||
@Override
|
||||
public void onPacketSending(final PacketEvent event) {
|
||||
final PacketContainer packet = event.getPacket();
|
||||
final Player player = event.getPlayer();
|
||||
if (player.hasPermission(BYPASS_PERMISSION)) {
|
||||
return;
|
||||
}
|
||||
final Entity entity = packet.getEntityModifier(event).read(0);
|
||||
if (!(entity instanceof LivingEntity)
|
||||
|| player.getEntityId() == entity.getEntityId()
|
||||
|| entity.getPassengers().contains(player)) {
|
||||
return;
|
||||
}
|
||||
final PacketContainer cloned = packet.deepClone();
|
||||
for (final WrappedWatchableObject object : cloned.getWatchableCollectionModifier().read(0)) {
|
||||
// Read the 8th field as a float as that's the living entity's health
|
||||
// https://wiki.vg/Entity_metadata#Living_Entity
|
||||
if (object.getIndex() == 9) {
|
||||
if ((float) object.getValue() > 0) {
|
||||
object.setValue(1f); // Half a heart
|
||||
}
|
||||
}
|
||||
}
|
||||
// The packet data is shared between events, but the event
|
||||
// instance is exclusive to THIS sending of the packet
|
||||
event.setPacket(cloned);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.packets.removeAllAdapters();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
private static boolean shouldBeObfuscated(final Material material) {
|
||||
return MaterialTags.HELMETS.isTagged(material)
|
||||
|| MaterialTags.CHEST_EQUIPPABLE.isTagged(material)
|
||||
|| MaterialTags.LEGGINGS.isTagged(material)
|
||||
|| MaterialTags.BOOTS.isTagged(material)
|
||||
|| MaterialTags.SWORDS.isTagged(material)
|
||||
|| MaterialTags.AXES.isTagged(material)
|
||||
|| MaterialTags.PICKAXES.isTagged(material)
|
||||
|| MaterialTags.SHOVELS.isTagged(material)
|
||||
|| MaterialTags.HOES.isTagged(material)
|
||||
|| material == Material.FIREWORK_ROCKET
|
||||
|| material == Material.WRITTEN_BOOK
|
||||
|| material == Material.ENCHANTED_BOOK
|
||||
|| material == Material.POTION
|
||||
|| material == Material.LINGERING_POTION
|
||||
|| material == Material.SPLASH_POTION;
|
||||
}
|
||||
|
||||
}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import vg.civcraft.mc.civmodcore.chat.ChatUtils;
|
||||
import vg.civcraft.mc.civmodcore.utilities.MoreCollectionUtils;
|
||||
|
||||
public final class AutoRespawn extends BasicHack {
|
||||
|
||||
private final Map<Player, RespawnTimer> respawnTimers = new HashMap<>();
|
||||
|
||||
@AutoLoad
|
||||
private long respawnDelay;
|
||||
|
||||
@AutoLoad
|
||||
private long loginRespawnDelay;
|
||||
|
||||
@AutoLoad
|
||||
private List<String> respawnQuotes;
|
||||
|
||||
public AutoRespawn(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
this.respawnDelay = Math.max(0L, this.respawnDelay);
|
||||
this.loginRespawnDelay = Math.max(0L, this.loginRespawnDelay);
|
||||
if (this.respawnQuotes == null) {
|
||||
this.respawnQuotes = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.respawnTimers.forEach((player, timer) -> timer.stop());
|
||||
this.respawnTimers.clear();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDeath(final PlayerDeathEvent event) {
|
||||
final Player player = event.getEntity();
|
||||
if (this.respawnDelay <= 0) {
|
||||
plugin().info("Player [" + player.getName() + "] died, respawning.");
|
||||
// This is necessary as respawning the player IMMEDIATELY means also not allowing the
|
||||
// death process to occur (such as dropping items) to occur prior to the respawn.
|
||||
Bukkit.getScheduler().runTask(this.plugin, () -> autoRespawnPlayer(player));
|
||||
}
|
||||
else {
|
||||
plugin().info("Player [" + player.getName() + "] died, " +
|
||||
"setting respawn timer: " + this.respawnDelay);
|
||||
this.respawnTimers.computeIfPresent(player, (_player, timer) -> timer.stop());
|
||||
this.respawnTimers.put(player, new RespawnTimer(this, player,
|
||||
this.respawnDelay, this::autoRespawnPlayer));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerLogin(final PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (!player.isDead()) {
|
||||
return;
|
||||
}
|
||||
if (this.loginRespawnDelay <= 0) {
|
||||
plugin().info("Player [" + player.getName() + "] logged in while dead, respawning.");
|
||||
// This is necessary as respawning the player IMMEDIATELY means also not allowing the
|
||||
// death process to occur (such as dropping items) to occur prior to the respawn.
|
||||
Bukkit.getScheduler().runTask(this.plugin, () -> autoRespawnPlayer(player));
|
||||
}
|
||||
else {
|
||||
plugin().info("Player [" + player.getName() + "] logged in while dead, " +
|
||||
"setting respawn timer: " + this.loginRespawnDelay);
|
||||
this.respawnTimers.computeIfPresent(player, (_player, timer) -> timer.stop());
|
||||
this.respawnTimers.put(player, new RespawnTimer(this, player,
|
||||
this.loginRespawnDelay, this::autoRespawnPlayer));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerLogout(final PlayerQuitEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (player.isDead()) {
|
||||
this.respawnTimers.computeIfPresent(player, (_player, timer) -> timer.stop());
|
||||
plugin().info("Player [" + player.getName() + "] logged out while dead.");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerRespawn(final PlayerRespawnEvent event) {
|
||||
this.respawnTimers.computeIfPresent(event.getPlayer(), (player, timer) -> timer.stop());
|
||||
}
|
||||
|
||||
private void autoRespawnPlayer(final Player player) {
|
||||
player.spigot().respawn();
|
||||
final String message = MoreCollectionUtils.randomElement(this.respawnQuotes);
|
||||
if (Strings.isNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
player.sendMessage(ChatUtils.parseColor(message));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Respawn Timer
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private static final class RespawnTimer {
|
||||
|
||||
private final Consumer<Player> handler;
|
||||
private BossBar bar;
|
||||
private long previousTime;
|
||||
private final long setTime;
|
||||
private long timeRemaining;
|
||||
private long secondTimer;
|
||||
private BukkitTask processor;
|
||||
|
||||
RespawnTimer(final AutoRespawn hack, final Player player, final long delay, final Consumer<Player> handler) {
|
||||
this.handler = handler;
|
||||
this.previousTime = System.currentTimeMillis();
|
||||
this.setTime = this.timeRemaining = delay;
|
||||
this.secondTimer = 1000L;
|
||||
this.bar = Bukkit.createBossBar(generateBarTitle(), BarColor.WHITE, BarStyle.SOLID);
|
||||
this.bar.setVisible(true);
|
||||
this.bar.setProgress(1.0d);
|
||||
this.bar.addPlayer(player);
|
||||
this.processor = new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
tick();
|
||||
}
|
||||
}.runTaskTimer(hack.plugin(), 1L, 1L);
|
||||
}
|
||||
|
||||
private String generateBarTitle() {
|
||||
if (this.timeRemaining <= 1000L) {
|
||||
return "Respawning now.";
|
||||
}
|
||||
if (this.timeRemaining < 60000L) {
|
||||
return "Respawning in " + (this.timeRemaining / 1000L) + " seconds.";
|
||||
}
|
||||
if (this.timeRemaining < 120000L) {
|
||||
return "Respawning in 1 minute.";
|
||||
}
|
||||
if (this.timeRemaining < 3600000L) {
|
||||
return "Respawning in " + (this.timeRemaining / 60000L) + " minutes.";
|
||||
}
|
||||
return "Respawning in " + (this.timeRemaining / 3600000L) + " hours.";
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long timeDifference = currentTime - this.previousTime;
|
||||
this.previousTime = currentTime;
|
||||
this.timeRemaining -= timeDifference;
|
||||
this.secondTimer -= timeDifference;
|
||||
if (this.secondTimer > 0) {
|
||||
return;
|
||||
}
|
||||
this.secondTimer = 1000L;
|
||||
this.bar.setTitle(generateBarTitle());
|
||||
this.bar.setProgress(Math.max((double) (this.timeRemaining - 1000L) / (double) this.setTime, 0));
|
||||
if (this.timeRemaining > 0) {
|
||||
return;
|
||||
}
|
||||
this.bar.getPlayers().forEach(this.handler);
|
||||
}
|
||||
|
||||
public RespawnTimer stop() {
|
||||
if (this.bar != null) {
|
||||
this.bar.setVisible(false);
|
||||
this.bar.removeAll();
|
||||
this.bar = null;
|
||||
}
|
||||
if (this.processor != null) {
|
||||
this.processor.cancel();
|
||||
this.processor = null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import vg.civcraft.mc.civmodcore.chat.Componentify;
|
||||
import vg.civcraft.mc.civmodcore.world.WorldUtils;
|
||||
|
||||
public final class BedLocator extends BasicHack {
|
||||
|
||||
private final BedLocatorCommand locatorCommand;
|
||||
|
||||
public BedLocator(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.locatorCommand = new BedLocatorCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
plugin().getCommands().registerCommand(this.locatorCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
plugin().getCommands().unregisterCommand(this.locatorCommand);
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@CommandPermission("simpleadmin.bedlocator")
|
||||
public static class BedLocatorCommand extends BaseCommand {
|
||||
@CommandAlias("wheresmybed|locatebed")
|
||||
@Description("Tells you where your bed is")
|
||||
public void giveWand(final Player sender) {
|
||||
final var bedLocation = sender.getBedSpawnLocation();
|
||||
if (bedLocation == null) {
|
||||
sender.sendMessage(Component.text("You do not a set bed.")
|
||||
.color(NamedTextColor.GREEN));
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(Component.text()
|
||||
.color(NamedTextColor.GREEN)
|
||||
.append(Component.text("Your bed is at "))
|
||||
.append(Componentify.blockLocation(bedLocation)));
|
||||
if (WorldUtils.doLocationsHaveSameWorld(sender.getLocation(), bedLocation)) {
|
||||
sender.sendMessage('['
|
||||
+ "name:Bed Location,"
|
||||
+ "x:" + bedLocation.getBlockX() + ','
|
||||
+ "y:" + bedLocation.getBlockY() + ','
|
||||
+ "z:" + bedLocation.getBlockZ()
|
||||
+ ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nonnull;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.animal.Bee;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
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.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityTargetEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import vg.civcraft.mc.civmodcore.chat.ChatUtils;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;
|
||||
import vg.civcraft.mc.civmodcore.utilities.MoreCollectionUtils;
|
||||
|
||||
public final class BeeKeeping extends BasicHack {
|
||||
|
||||
private static final Random RANDOM = new SecureRandom();
|
||||
|
||||
public BeeKeeping(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Natural Bee Spawning
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private static final Set<EntityType> NEUTRAL_MOBS = Set.of(
|
||||
EntityType.CHICKEN,
|
||||
EntityType.COW,
|
||||
EntityType.PIG,
|
||||
EntityType.SHEEP,
|
||||
EntityType.RABBIT);
|
||||
|
||||
@AutoLoad
|
||||
private double spawnChance;
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void beeSpawning(final CreatureSpawnEvent event) {
|
||||
if (!NEUTRAL_MOBS.contains(event.getEntityType())
|
||||
|| event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.NATURAL
|
||||
|| this.spawnChance <= 0.0d
|
||||
|| (this.spawnChance < 1.0d && RANDOM.nextDouble() > this.spawnChance)) {
|
||||
return;
|
||||
}
|
||||
final Location location = event.getLocation();
|
||||
final World world = location.getWorld();
|
||||
world.spawnEntity(location, EntityType.BEE);
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Bee Combat
|
||||
// ------------------------------------------------------------
|
||||
|
||||
@AutoLoad
|
||||
private double severStingerChance;
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void attackedByBee(final EntityDamageByEntityEvent event) {
|
||||
final Entity attacker = event.getDamager();
|
||||
if (attacker.getType() != EntityType.BEE
|
||||
|| event.getCause() != EntityDamageEvent.DamageCause.ENTITY_ATTACK // Ignore if not attacked
|
||||
|| this.severStingerChance >= 1.0d // Ignore if severance is guaranteed
|
||||
|| (this.severStingerChance > 0.0d && RANDOM.nextDouble() <= this.severStingerChance)) {
|
||||
return;
|
||||
}
|
||||
final Bee bee = (Bee) ((CraftEntity) attacker).getHandle();
|
||||
// Undo bee pacification and allow the bee to sting again
|
||||
/** See the code in {@link IEntityAngerable#pacify()} */
|
||||
final var lastDamageCause = bee.getLastHurtByMob();
|
||||
final var angerTarget = bee.getPersistentAngerTarget();
|
||||
final var goalTarget = bee.getTarget();
|
||||
final var angerLevel = bee.getRemainingPersistentAngerTime();
|
||||
Bukkit.getScheduler().runTask(this.plugin, () -> {
|
||||
bee.setHasStung(false);
|
||||
// Reset the above values
|
||||
bee.setLastHurtByMob(lastDamageCause);
|
||||
bee.setPersistentAngerTarget(angerTarget);
|
||||
bee.setTarget(goalTarget, EntityTargetEvent.TargetReason.FORGOT_TARGET, false); // Params: target, cause, emit event
|
||||
bee.setRemainingPersistentAngerTime(angerLevel);
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Bee Hive/Nest Details
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private static final String BEES_LIST_KEY = "Bees";
|
||||
private static final String BEE_DATA_KEY = "EntityData";
|
||||
private static final String BEE_NAME_KEY = "CustomName";
|
||||
|
||||
private static final Set<Material> HIVE_MATERIALS = Set.of(
|
||||
Material.BEE_NEST,
|
||||
Material.BEEHIVE);
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void showHiveDetails(final PlayerInteractEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
final ItemStack held = event.getItem();
|
||||
if (ItemUtils.isValidItem(held)) {
|
||||
return;
|
||||
}
|
||||
final Block block = Objects.requireNonNull(event.getClickedBlock());
|
||||
if (!HIVE_MATERIALS.contains(block.getType())) {
|
||||
return;
|
||||
}
|
||||
final BeehiveBlockEntity beehive = getBeeHive(block);
|
||||
if (beehive.isEmpty()) {
|
||||
player.sendMessage(ChatColor.GOLD + "There aren't any bees in that hive.");
|
||||
return;
|
||||
}
|
||||
final List<BeeData> bees = getBeesFromHive(beehive);
|
||||
final int numberOfUnnamed = MoreCollectionUtils.numberOfMatches(bees, BeeData::isNameless);
|
||||
bees.removeIf(BeeData::isNameless);
|
||||
// Start building response
|
||||
final var response = Component.text().color(NamedTextColor.GOLD);
|
||||
final Iterator<BeeData> nameIterator = bees.iterator();
|
||||
boolean doneFirstElement = false;
|
||||
while (nameIterator.hasNext()) {
|
||||
final BeeData bee = nameIterator.next();
|
||||
if (nameIterator.hasNext() || numberOfUnnamed > 0) {
|
||||
if (doneFirstElement) {
|
||||
response.append(Component.text(", "));
|
||||
}
|
||||
}
|
||||
else if (numberOfUnnamed == 0) {
|
||||
response.append(Component.text(", and "));
|
||||
}
|
||||
assert bee.name != null;
|
||||
response.append(bee.name);
|
||||
doneFirstElement = true;
|
||||
}
|
||||
if (numberOfUnnamed > 0) {
|
||||
if (bees.isEmpty()) {
|
||||
response.append(Component.text("There are " + numberOfUnnamed + " bees"));
|
||||
}
|
||||
else {
|
||||
response.append(Component.text(", and " + numberOfUnnamed + " others are"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
response.append(Component.text(" are"));
|
||||
}
|
||||
if (beehive.isSedated()) {
|
||||
response.append(Component.text(" sedated"));
|
||||
}
|
||||
else {
|
||||
response.append(Component.text(" happily buzzing"));
|
||||
}
|
||||
response.append(Component.text(" in that hive."));
|
||||
player.sendMessage(response);
|
||||
}
|
||||
|
||||
private static BeehiveBlockEntity getBeeHive(@Nonnull final Block block) {
|
||||
final CraftBlock craftBlock = (CraftBlock) block;
|
||||
final CraftWorld craftWorld = craftBlock.getCraftWorld();
|
||||
final ServerLevel worldServer = craftWorld.getHandle();
|
||||
final BlockEntity tileEntity = worldServer.getBlockEntity(craftBlock.getPosition());
|
||||
return (BeehiveBlockEntity) Objects.requireNonNull(tileEntity);
|
||||
}
|
||||
|
||||
private static List<BeeData> getBeesFromHive(@Nonnull final BeehiveBlockEntity hive) {
|
||||
return hive.writeBees().stream()
|
||||
.map(bee -> ((CompoundTag) bee).getCompound(BEE_DATA_KEY))
|
||||
.map(BeeData::new)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
private static final class BeeData {
|
||||
|
||||
public final Component name;
|
||||
|
||||
public BeeData(@Nonnull final CompoundTag nbt) {
|
||||
// Parse name
|
||||
final String rawName = nbt.getString(BEE_NAME_KEY);
|
||||
if (Strings.isNullOrEmpty(rawName)) {
|
||||
this.name = null;
|
||||
}
|
||||
else {
|
||||
final var componentName = GsonComponentSerializer.gson().deserialize(rawName);
|
||||
this.name = ChatUtils.isNullOrEmpty(componentName) ? null : componentName;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNameless() {
|
||||
return this.name == null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import static org.bukkit.event.entity.EntityPotionEffectEvent.Action;
|
||||
import static org.bukkit.event.entity.EntityPotionEffectEvent.Cause;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.DataParser;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
public final class BuffSpanker extends BasicHack {
|
||||
|
||||
@AutoLoad(id = "naughty", processor = DataParser.POTION_EFFECT_TYPE)
|
||||
private List<PotionEffectType> naughtyEffects;
|
||||
|
||||
public BuffSpanker(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
if (this.naughtyEffects == null) {
|
||||
this.naughtyEffects = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.naughtyEffects.clear();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void whenPotionEffectsChange(final EntityPotionEffectEvent event) {
|
||||
final PotionEffect effect = event.getNewEffect();
|
||||
if (effect == null || event.getAction() != Action.ADDED || event.getCause() == Cause.PLUGIN) {
|
||||
return;
|
||||
}
|
||||
if (this.naughtyEffects.contains(effect.getType())) {
|
||||
plugin().debug("Prevented [" + effect.getType().getName() + "] on: " + event.getEntity().getName());
|
||||
event.setCancelled(true);
|
||||
//return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import java.util.Objects;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import vg.civcraft.mc.civmodcore.commands.CommandManager;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;
|
||||
|
||||
public final class DebugWand extends BasicHack {
|
||||
|
||||
private static final String PERMISSION = "simpleadmin.debugwand";
|
||||
private static final ItemStack WAND = new ItemStack(Material.BLAZE_ROD);
|
||||
|
||||
static {
|
||||
ItemUtils.setDisplayName(WAND, ChatColor.GOLD + "Block Wand");
|
||||
}
|
||||
|
||||
private final CommandManager commands;
|
||||
|
||||
public DebugWand(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.commands = new CommandManager(plugin) {
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
registerCommand(new WandCommand());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
this.commands.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.commands.reset();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@CommandPermission(PERMISSION)
|
||||
public static class WandCommand extends BaseCommand {
|
||||
@CommandAlias("debugwand|dbwand")
|
||||
@Description("Creates a wand for debugging")
|
||||
public void giveWand(final Player sender) {
|
||||
sender.getInventory().addItem(WAND.clone());
|
||||
sender.sendMessage(ChatColor.GREEN + "Wand created.");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onWandUsageOnBlock(final PlayerInteractEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (!player.hasPermission(PERMISSION)) {
|
||||
return;
|
||||
}
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
final ItemStack held = event.getItem();
|
||||
if (!ItemUtils.isValidItem(held) || !ItemUtils.areItemsSimilar(held, WAND)) {
|
||||
return;
|
||||
}
|
||||
final Block block = Objects.requireNonNull(event.getClickedBlock());
|
||||
final Location blockLocation = block.getLocation();
|
||||
player.sendMessage(ChatColor.GREEN + "Debug start.");
|
||||
player.sendMessage(ChatColor.AQUA + "Material: " + ChatColor.WHITE + block.getType().name());
|
||||
player.sendMessage(ChatColor.AQUA + "Location: "
|
||||
+ ChatColor.RED + "x:" + blockLocation.getBlockX() + ChatColor.WHITE + ", "
|
||||
+ ChatColor.GREEN + "y:" + blockLocation.getBlockY() + ChatColor.WHITE + ", "
|
||||
+ ChatColor.BLUE + "z:" + blockLocation.getBlockZ());
|
||||
final BlockData data = block.getBlockData();
|
||||
player.sendMessage(ChatColor.AQUA + "Block Data: " + ChatColor.YELLOW + data.getClass().getName());
|
||||
player.sendMessage(data.toString());
|
||||
player.sendMessage(ChatColor.RED + "Data end.");
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onWandUsageOnEntity(final PlayerInteractEntityEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (!player.hasPermission(PERMISSION)) {
|
||||
return;
|
||||
}
|
||||
final ItemStack held = player.getInventory().getItem(event.getHand());
|
||||
if (!ItemUtils.isValidItem(held) || !ItemUtils.areItemsSimilar(held, WAND)) {
|
||||
return;
|
||||
}
|
||||
final Entity entity = event.getRightClicked();
|
||||
final Location entityLocation = entity.getLocation();
|
||||
player.sendMessage(ChatColor.GREEN + "Debug start.");
|
||||
player.sendMessage(ChatColor.AQUA + "Entity: " + ChatColor.WHITE + entity.getType().name());
|
||||
player.sendMessage(ChatColor.AQUA + "Location: "
|
||||
+ ChatColor.RED + "x:" + entityLocation.getX() + ChatColor.WHITE + ", "
|
||||
+ ChatColor.GREEN + "y:" + entityLocation.getY() + ChatColor.WHITE + ", "
|
||||
+ ChatColor.BLUE + "z:" + entityLocation.getZ());
|
||||
player.sendMessage(ChatColor.AQUA + "Rotation: "
|
||||
+ ChatColor.YELLOW + "p:" + entityLocation.getPitch() + ", "
|
||||
+ ChatColor.GOLD + "y:" + entityLocation.getYaw());
|
||||
final CompoundTag nbt = new CompoundTag();
|
||||
((CraftEntity) entity).getHandle().save(nbt);
|
||||
nbt.remove("Pos"); // Remove redundant position
|
||||
nbt.remove("Rotation"); // Remove redundant rotation
|
||||
player.sendMessage(nbt.toString());
|
||||
player.sendMessage(ChatColor.RED + "Data end.");
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import vg.civcraft.mc.civmodcore.config.ConfigHelper;
|
||||
import vg.civcraft.mc.civmodcore.players.settings.PlayerSettingAPI;
|
||||
import vg.civcraft.mc.civmodcore.players.settings.gui.MenuSection;
|
||||
import vg.civcraft.mc.civmodcore.players.settings.impl.BooleanSetting;
|
||||
|
||||
public class DogFacts extends BasicHack {
|
||||
|
||||
@AutoLoad
|
||||
private List<String> announcements;
|
||||
@AutoLoad
|
||||
private String intervalTime;
|
||||
private BooleanSetting disableAnnouncements;
|
||||
private int counter = 0;
|
||||
|
||||
public DogFacts(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
startRunnable(announcements);
|
||||
initSettings();
|
||||
}
|
||||
|
||||
public void startRunnable(List<String> announcements){
|
||||
long interval = ConfigHelper.parseTimeAsTicks(intervalTime);
|
||||
int tickOffset = (int) (Math.random() * (interval));
|
||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin ,() -> {
|
||||
if (announcements.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (counter >= announcements.size()) {
|
||||
counter = 0;
|
||||
}
|
||||
String message = announcements.get(counter);
|
||||
plugin.info("Broadcasting DogFact #" + counter);
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (getDisableAnnouncements(player.getUniqueId())){
|
||||
continue;
|
||||
}
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + player.getDisplayName() + " " + message);
|
||||
}
|
||||
counter++;
|
||||
}, tickOffset, interval);
|
||||
}
|
||||
|
||||
private void initSettings() {
|
||||
MenuSection menu = plugin.getSettingManager().getMainMenu();
|
||||
disableAnnouncements =
|
||||
new BooleanSetting(plugin, false, "Disable Announcements", "disableAnnouncements",
|
||||
"Disable Announcements?");
|
||||
PlayerSettingAPI.registerSetting(disableAnnouncements, menu);
|
||||
}
|
||||
|
||||
public boolean getDisableAnnouncements(UUID uuid) {
|
||||
return disableAnnouncements.getValue(uuid);
|
||||
}
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.EventExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
|
||||
public class EventDebugHack extends BasicHack {
|
||||
|
||||
private Map<Class<?>, List<RegisteredListener>> classToListeners;
|
||||
private Map<Class<?>, HandlerList> classToHandler;
|
||||
|
||||
public EventDebugHack(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
classToListeners = new HashMap<>();
|
||||
classToHandler = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
plugin().registerCommand("debugevent", new CommandExecutor() {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command arg1, String arg2, String[] args) {
|
||||
if (args.length == 0) {
|
||||
sender.sendMessage(ChatColor.RED + "You must give an event");
|
||||
return false;
|
||||
}
|
||||
if (untargetEvent(args[0])) {
|
||||
sender.sendMessage(ChatColor.GREEN + "Disabled tracking for " + args[0]);
|
||||
return true;
|
||||
}
|
||||
targetEvent(args[0], sender);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean untargetEvent(String eventName) {
|
||||
Class<? extends Event> eventClass = getEventClass(eventName);
|
||||
if (eventClass == null) {
|
||||
return false;
|
||||
}
|
||||
HandlerList handler = classToHandler.get(eventClass);
|
||||
List<RegisteredListener> listeners = classToListeners.get(eventClass);
|
||||
if (handler == null || listeners == null) {
|
||||
return false;
|
||||
}
|
||||
listeners.forEach(handler::unregister);
|
||||
classToHandler.remove(eventClass);
|
||||
classToListeners.remove(eventClass);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Class<? extends Event> getEventClass(String eventName) {
|
||||
if (eventName.startsWith(".")) {
|
||||
eventName = "org.bukkit.event" + eventName;
|
||||
}
|
||||
try {
|
||||
return (Class<Event>) Class.forName(eventName);
|
||||
} catch (ClassCastException | ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void targetEvent(String eventName, CommandSender sender) {
|
||||
Class<? extends Event> eventClass = getEventClass(eventName);
|
||||
if (eventClass == null) {
|
||||
sender.sendMessage(ChatColor.RED + "No event class with that path exists");
|
||||
return;
|
||||
}
|
||||
if (classToHandler.containsKey(eventClass)) {
|
||||
sender.sendMessage(ChatColor.RED + "Event is already being investigated");
|
||||
return;
|
||||
}
|
||||
Method handlerGetter;
|
||||
try {
|
||||
handlerGetter = eventClass.getMethod("getHandlerList");
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
sender.sendMessage(ChatColor.RED + "The class did not have a handler getter");
|
||||
return;
|
||||
}
|
||||
if (handlerGetter.getReturnType() != HandlerList.class) {
|
||||
sender.sendMessage(ChatColor.RED + "Getter had wrong return type");
|
||||
return;
|
||||
}
|
||||
HandlerList handlerList;
|
||||
try {
|
||||
handlerList = (HandlerList) handlerGetter.invoke(eventClass);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Could not invoke handler getter");
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(
|
||||
ChatColor.GOLD + "Currently registered listeners for " + eventClass.getSimpleName() + " are:");
|
||||
for (RegisteredListener listener : handlerList.getRegisteredListeners()) {
|
||||
for (Method method : listener.getListener().getClass().getMethods()) {
|
||||
if (method.isBridge() || method.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
if (!method.isAnnotationPresent(EventHandler.class)) {
|
||||
continue;
|
||||
}
|
||||
if (method.getParameterCount() != 1) {
|
||||
continue;
|
||||
}
|
||||
Class<?> clazz = method.getParameterTypes()[0];
|
||||
if (clazz != eventClass) {
|
||||
continue;
|
||||
}
|
||||
sender.sendMessage(String.format("[%s] on %s is %s", listener.getPlugin().getName(),
|
||||
listener.getPriority(), listener.getListener().getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
Listener fakeListener = new Listener() {
|
||||
};
|
||||
// need to hack our listener in, because can't dynamically declare an actual
|
||||
// class with annotations etc.
|
||||
List<RegisteredListener> listeners = new LinkedList<>();
|
||||
for (EventPriority prio : EventPriority.values()) {
|
||||
RegisteredListener listener = new RegisteredListener(fakeListener, new EventExecutor() {
|
||||
|
||||
@Override
|
||||
public void execute(Listener arg0, Event arg1) throws EventException {
|
||||
printEventState(prio, arg1);
|
||||
}
|
||||
}, prio, SimpleAdminHacks.instance(), false);
|
||||
listeners.add(listener);
|
||||
handlerList.register(listener);
|
||||
}
|
||||
classToHandler.put(eventClass, handlerList);
|
||||
classToListeners.put(eventClass, listeners);
|
||||
}
|
||||
|
||||
private void printEventState(EventPriority prio, Event event) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("At stage " + prio.toString() + " " + event.getEventName() + " is as follows: \n");
|
||||
deepInspectObject(event, "event", sb, 0, new HashSet<>());
|
||||
SimpleAdminHacks.instance().getLogger().info(sb.toString());
|
||||
}
|
||||
|
||||
private static void deepInspectObject(Object o, String fieldName, StringBuilder sb, int depth, Set<Object> seen) {
|
||||
String pre = new String(new char[depth * 2]).replace("\0", "-") + " ";
|
||||
if (o == null) {
|
||||
sb.append(pre + fieldName + ": null\n");
|
||||
return;
|
||||
}
|
||||
if (ClassUtils.isPrimitiveOrWrapper(o.getClass()) || straightPrint(o)) {
|
||||
sb.append(pre + o.getClass().getSimpleName() + " " + fieldName + " = " + o.toString() + '\n');
|
||||
return;
|
||||
}
|
||||
sb.append(pre + o.getClass().getSimpleName() + " " + fieldName + ":");
|
||||
if (seen.contains(o)) {
|
||||
sb.append(pre + "omitted\n");
|
||||
return;
|
||||
} else {
|
||||
sb.append('\n');
|
||||
}
|
||||
seen.add(o);
|
||||
for (Field field : getAllFields(new LinkedList<>(), o.getClass())) {
|
||||
field.setAccessible(true);
|
||||
Object member;
|
||||
try {
|
||||
member = field.get(o);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
SimpleAdminHacks.instance().getLogger()
|
||||
.severe("Failed to get member in deep inspection " + e.getMessage());
|
||||
continue;
|
||||
}
|
||||
deepInspectObject(member, field.getName(), sb, depth + 1, seen);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
|
||||
fields.addAll(Arrays.asList(type.getDeclaredFields()));
|
||||
if (type.getSuperclass() != null) {
|
||||
getAllFields(fields, type.getSuperclass());
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
private static boolean straightPrint(Object o) {
|
||||
return o instanceof Entity || o instanceof String || o instanceof World || o instanceof Plugin
|
||||
|| o instanceof Collection || o instanceof Map || o instanceof Server || o instanceof Location
|
||||
|| o instanceof Block || o.getClass().isEnum() || o instanceof HandlerList || o instanceof Random
|
||||
|| o instanceof Logger || o instanceof ItemStack;
|
||||
}
|
||||
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.BukkitCommandCompletionContext;
|
||||
import co.aikar.commands.InvalidCommandArgument;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.google.common.base.Strings;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import vg.civcraft.mc.civmodcore.commands.CommandManager;
|
||||
import vg.civcraft.mc.civmodcore.commands.TabComplete;
|
||||
|
||||
public final class EventHandlerList extends BasicHack {
|
||||
|
||||
private final CommandManager commands;
|
||||
private final HandlersList handlers;
|
||||
|
||||
public EventHandlerList(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.handlers = new HandlersList();
|
||||
this.commands = new CommandManager(plugin) {
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
registerCommand(new HandlersCommand(handlers));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
this.commands.init();
|
||||
this.plugin.registerListener(this.handlers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
HandlerList.unregisterAll(this.handlers);
|
||||
this.commands.reset();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Handlers Command
|
||||
// ------------------------------------------------------------
|
||||
|
||||
@CommandPermission("simpleadmin.eventdebug")
|
||||
private static final class HandlersCommand extends BaseCommand {
|
||||
|
||||
private final HandlersList handlers;
|
||||
|
||||
public HandlersCommand(final HandlersList handlers) {
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
@CommandAlias("handlers|handler|listeners|listener")
|
||||
@Description("Gets the details for a handler.")
|
||||
@Syntax("<handler>")
|
||||
@CommandCompletion("@handlers")
|
||||
public void onListHandlers(final CommandSender sender, @Single final String handler) {
|
||||
if (Strings.isNullOrEmpty(handler)) {
|
||||
throw new InvalidCommandArgument("Please enter an event handler.");
|
||||
}
|
||||
sender.sendMessage(ChatColor.GOLD + "Getting handlers for: " + ChatColor.WHITE + handler);
|
||||
for (final Map.Entry<Class<? extends Event>, Map<Plugin, Set<Class<? extends Listener>>>> entry :
|
||||
this.handlers.getHandlerCache().entrySet()) {
|
||||
if (!StringUtils.equals(entry.getKey().getName(), handler)) {
|
||||
continue;
|
||||
}
|
||||
for (final Map.Entry<Plugin, Set<Class<? extends Listener>>> details : entry.getValue().entrySet()) {
|
||||
sender.sendMessage(ChatColor.LIGHT_PURPLE + details.getKey().getName() + ":");
|
||||
for (final Class<? extends Listener> clazz : details.getValue()) {
|
||||
sender.sendMessage(" - " + clazz.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
sender.sendMessage(ChatColor.AQUA + "End of handlers.");
|
||||
}
|
||||
|
||||
@TabComplete("handlers")
|
||||
public List<String> tabCompleteEvents(final BukkitCommandCompletionContext context) {
|
||||
final List<String> results = new ArrayList<>();
|
||||
for (final Class<? extends Event> clazz : this.handlers.getHandlerCache().keySet()) {
|
||||
final String path = clazz.getName();
|
||||
if (!StringUtils.startsWith(path, context.getInput())) {
|
||||
continue;
|
||||
}
|
||||
results.add(path);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Handlers List
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private static final class HandlersList implements Listener {
|
||||
|
||||
private final Map<Class<? extends Event>, Map<Plugin, Set<Class<? extends Listener>>>> handlers;
|
||||
private boolean handlersCollected;
|
||||
|
||||
public HandlersList() {
|
||||
this.handlers = new HashMap<>();
|
||||
this.handlersCollected = false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<Class<? extends Event>, Map<Plugin, Set<Class<? extends Listener>>>> getHandlerCache() {
|
||||
if (!this.handlersCollected) {
|
||||
this.handlers.clear();
|
||||
for (final HandlerList handlers : HandlerList.getHandlerLists()) {
|
||||
for (final RegisteredListener listener : handlers.getRegisteredListeners()) {
|
||||
for (final Method method : listener.getListener().getClass().getMethods()) {
|
||||
if (method.isBridge() || method.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
if (!method.isAnnotationPresent(EventHandler.class)) {
|
||||
continue;
|
||||
}
|
||||
if (method.getParameterCount() != 1) {
|
||||
continue;
|
||||
}
|
||||
final Class<?> clazz = method.getParameterTypes()[0];
|
||||
if (!Event.class.isAssignableFrom(clazz)) {
|
||||
continue;
|
||||
}
|
||||
this.handlers.
|
||||
computeIfAbsent((Class<? extends Event>) clazz, (k) -> new HashMap<>()).
|
||||
computeIfAbsent(listener.getPlugin(), (k) -> new HashSet<>()).
|
||||
add(listener.getListener().getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.handlersCollected = true;
|
||||
}
|
||||
return this.handlers;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginEnable(final PluginEnableEvent event) {
|
||||
this.handlersCollected = false;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginDisable(final PluginDisableEvent event) {
|
||||
this.handlersCollected = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerJumpEvent;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.TeleportUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
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.event.player.PlayerToggleSneakEvent;
|
||||
import vg.civcraft.mc.civmodcore.players.settings.PlayerSettingAPI;
|
||||
import vg.civcraft.mc.civmodcore.players.settings.gui.MenuSection;
|
||||
import vg.civcraft.mc.civmodcore.players.settings.impl.BooleanSetting;
|
||||
import vg.civcraft.mc.civmodcore.utilities.DoubleInteractFixer;
|
||||
|
||||
public class GoldBlockElevators extends BasicHack {
|
||||
|
||||
private BooleanSetting useJumpSneakTP;
|
||||
private DoubleInteractFixer interactFixer;
|
||||
|
||||
public GoldBlockElevators(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.interactFixer = new DoubleInteractFixer(plugin);
|
||||
initSettings();
|
||||
}
|
||||
|
||||
private void initSettings() {
|
||||
MenuSection mainMenu = plugin.getSettingManager().getMainMenu();
|
||||
this.useJumpSneakTP =
|
||||
new BooleanSetting(plugin, true, "Use Jump or Sneak to teleport on gold blocks", "jumpOrSneakTp",
|
||||
"When true, jumping or sneaking on gold blocks will teleport you up/down, when false, right or left clicking will do the same.");
|
||||
PlayerSettingAPI.registerSetting(this.useJumpSneakTP, mainMenu);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void goldBlockSneak(PlayerToggleSneakEvent event) {
|
||||
if (!this.useJumpSneakTP.getValue(event.getPlayer())) {
|
||||
return;
|
||||
}
|
||||
Block below = event.getPlayer().getLocation().getBlock().getRelative(BlockFace.DOWN);
|
||||
if (below.getType() != Material.GOLD_BLOCK) {
|
||||
return;
|
||||
}
|
||||
if (!event.isSneaking()) {
|
||||
return;
|
||||
}
|
||||
for (int y = (below.getY() - 1); y > below.getWorld().getMinHeight(); y--) {
|
||||
if (doTeleport(below, event.getPlayer(), y)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
event.getPlayer().sendMessage(
|
||||
ChatColor.RED + "No gold block to teleport you down to. Jump to teleport up instead.");
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void goldBlockJump(PlayerJumpEvent event) {
|
||||
if (!this.useJumpSneakTP.getValue(event.getPlayer())) {
|
||||
return;
|
||||
}
|
||||
Block below = event.getFrom().getBlock().getRelative(BlockFace.DOWN);
|
||||
if (below.getType() != Material.GOLD_BLOCK) {
|
||||
return;
|
||||
}
|
||||
for (int y = below.getY() + 1; y <= below.getWorld().getMaxHeight(); y++) {
|
||||
if (doTeleport(below, event.getPlayer(), y)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
event.getPlayer()
|
||||
.sendMessage(ChatColor.RED + "No gold block to teleport you up to. Sneak to teleport down instead.");
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void goldBlockInteract(PlayerInteractEvent event) {
|
||||
if (this.useJumpSneakTP.getValue(event.getPlayer())) {
|
||||
return;
|
||||
}
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
if (interactFixer.checkInteracted(event.getPlayer(), event.getClickedBlock())) {
|
||||
return;
|
||||
}
|
||||
} else if (event.getAction() != Action.LEFT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
Block below = event.getPlayer().getLocation().getBlock().getRelative(BlockFace.DOWN);
|
||||
if (below.getType() != Material.GOLD_BLOCK) {
|
||||
return;
|
||||
}
|
||||
if (event.getClickedBlock() == null) {
|
||||
return;
|
||||
}
|
||||
if (!event.getClickedBlock().equals(below)) {
|
||||
return;
|
||||
}
|
||||
if (event.getAction() == Action.LEFT_CLICK_BLOCK) {
|
||||
for (int y = below.getY() - 1; y > below.getWorld().getMinHeight(); y--) {
|
||||
if (doTeleport(below, event.getPlayer(), y)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
event.getPlayer().sendMessage(
|
||||
Component.text("No gold block to teleport you down to. Right click to teleport up instead.")
|
||||
.color(NamedTextColor.RED));
|
||||
} else {
|
||||
for (int y = below.getY() + 1; y <= below.getWorld().getMaxHeight(); y++) {
|
||||
if (doTeleport(below, event.getPlayer(), y)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
event.getPlayer().sendMessage(
|
||||
Component.text("No gold block to teleport you up to. Left click to teleport down instead.")
|
||||
.color(NamedTextColor.RED));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doTeleport(Block source, Player player, int y) {
|
||||
Block target = source.getWorld().getBlockAt(source.getX(), y, source.getZ());
|
||||
if (target.getType() != Material.GOLD_BLOCK) {
|
||||
return false;
|
||||
}
|
||||
if (!TeleportUtil.checkForTeleportSpace(target.getRelative(BlockFace.UP).getLocation())) {
|
||||
return false;
|
||||
}
|
||||
source.getWorld().playSound(source.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1.0F, 8.0F);
|
||||
Location adjustedLocation = target.getLocation().clone();
|
||||
adjustedLocation.add(0.5, 1.02, 0.5);
|
||||
adjustedLocation.setYaw(player.getLocation().getYaw());
|
||||
adjustedLocation.setPitch(player.getLocation().getPitch());
|
||||
player.playSound(adjustedLocation, Sound.ENTITY_ENDERMAN_TELEPORT, 1.0F, 8.0F);
|
||||
player.teleport(adjustedLocation);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+411
@@ -0,0 +1,411 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.Levelled;
|
||||
import org.bukkit.entity.EntityType;
|
||||
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.BlockPhysicsEvent;
|
||||
import org.bukkit.event.block.CauldronLevelChangeEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityPotionEffectEvent;
|
||||
import org.bukkit.event.entity.EntityPotionEffectEvent.Cause;
|
||||
import org.bukkit.event.entity.EntitySpawnEvent;
|
||||
import org.bukkit.event.entity.SheepDyeWoolEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import vg.civcraft.mc.civmodcore.world.WorldUtils;
|
||||
|
||||
public class HumbugBatchOne extends BasicHack {
|
||||
|
||||
@AutoLoad
|
||||
private boolean allowSheepDying;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableGapples;
|
||||
|
||||
@AutoLoad
|
||||
private boolean allowUsingAnvils;
|
||||
@AutoLoad
|
||||
private boolean allowUsingEnchantingTables;
|
||||
|
||||
@AutoLoad
|
||||
private boolean infiniteCauldrons;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableEnderDragon;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableIronFarms;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableEnderCrystalDamage;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableMiningFatigue;
|
||||
|
||||
@AutoLoad
|
||||
private boolean canEquipBanners;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableLavaCobbleMountains;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableWanderingTrader;
|
||||
|
||||
@AutoLoad
|
||||
private boolean preventPearlGlitching;
|
||||
|
||||
@AutoLoad
|
||||
private boolean preventUsingEyeOfEnder;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableEndGatewayTP;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disablePiglins;
|
||||
|
||||
public HumbugBatchOne(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onDyeWool(SheepDyeWoolEvent event) {
|
||||
if (!allowSheepDying) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onDisallowedBlockUse(PlayerInteractEvent event) {
|
||||
if (event.getClickedBlock() == null) {
|
||||
return;
|
||||
}
|
||||
Material mat = event.getClickedBlock().getType();
|
||||
if (!allowUsingEnchantingTables
|
||||
&& (mat == Material.ANVIL || mat == Material.CHIPPED_ANVIL || mat == Material.DAMAGED_ANVIL)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (!allowUsingEnchantingTables && mat == Material.ENCHANTING_TABLE) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void disableGapples(PlayerItemConsumeEvent event) {
|
||||
if(!disableGapples) {
|
||||
return;
|
||||
}
|
||||
if(event.getItem().getType() == Material.ENCHANTED_GOLDEN_APPLE) {
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage(ChatColor.RED + "You are not allowed to eat Golden Apples.");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void cauldronEmpty(CauldronLevelChangeEvent e) {
|
||||
if (infiniteCauldrons && e.getReason() == CauldronLevelChangeEvent.ChangeReason.BOTTLE_FILL) {
|
||||
e.setNewLevel(e.getOldLevel());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void preventEndCrystalUsage(PlayerInteractEvent e) {
|
||||
if (!disableEnderDragon) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.getItem() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player p = e.getPlayer();
|
||||
Environment env = p.getWorld().getEnvironment();
|
||||
|
||||
if (!(env == Environment.THE_END)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.getAction() == Action.RIGHT_CLICK_BLOCK && e.getItem().getType() == Material.END_CRYSTAL) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage(ChatColor.RED + "Sorry, placing end crystals is disabled in this world!");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void gatewayTP(PlayerTeleportEvent e) {
|
||||
if (!disableEndGatewayTP) {
|
||||
return;
|
||||
}
|
||||
if (e.getCause() == TeleportCause.END_GATEWAY) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage(ChatColor.RED + "Sorry, these are disabled");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
||||
public void golemDeath(EntityDeathEvent e) {
|
||||
if (!disableIronFarms) {
|
||||
return;
|
||||
}
|
||||
if (e.getEntity().getType() != EntityType.IRON_GOLEM) {
|
||||
return;
|
||||
}
|
||||
Iterator<ItemStack> iter = e.getDrops().iterator();
|
||||
while (iter.hasNext()) {
|
||||
ItemStack is = iter.next();
|
||||
if (is.getType() == Material.IRON_INGOT) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void disableEnderCrystal(EntityDamageByEntityEvent e) {
|
||||
if (disableEnderCrystalDamage && e.getDamager().getType() == EntityType.ENDER_CRYSTAL) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void adminAccessBlockedChest(PlayerInteractEvent e) {
|
||||
if (!e.getPlayer().hasPermission("simpleadmin.chestsee") && !e.getPlayer().isOp()) {
|
||||
return;
|
||||
}
|
||||
if (e.getAction() != Action.RIGHT_CLICK_AIR && e.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
Player p = e.getPlayer();
|
||||
Set<Material> s = new TreeSet<>();
|
||||
s.add(Material.AIR);
|
||||
s.add(Material.OBSIDIAN); // probably in a vault
|
||||
List<Block> blocks = p.getLineOfSight(s, 8);
|
||||
for (Block b : blocks) {
|
||||
Material m = b.getType();
|
||||
if (m == Material.CHEST || m == Material.TRAPPED_CHEST) {
|
||||
if (b.getRelative(BlockFace.UP).getType().isOccluding()) {
|
||||
// dont show inventory twice if a normal chest is opened
|
||||
final Inventory chestInv = ((InventoryHolder) b.getState()).getInventory();
|
||||
p.openInventory(chestInv);
|
||||
p.updateInventory();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void potionEffect(EntityPotionEffectEvent event) {
|
||||
if (!disableMiningFatigue) {
|
||||
return;
|
||||
}
|
||||
if (event.getAction() == org.bukkit.event.entity.EntityPotionEffectEvent.Action.REMOVED || event.getCause() == Cause.PLUGIN) {
|
||||
return;
|
||||
}
|
||||
if (event.getModifiedType() == PotionEffectType.SLOW_DIGGING) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void equipBanner(PlayerInteractEvent event) {
|
||||
if (!canEquipBanners) {
|
||||
return;
|
||||
}
|
||||
if (event.getItem() == null || !Tag.BANNERS.isTagged(event.getItem().getType()) // API
|
||||
|| (event.getAction() != Action.LEFT_CLICK_AIR && event.getAction() != Action.LEFT_CLICK_BLOCK)) {
|
||||
return;
|
||||
}
|
||||
Player player = event.getPlayer();
|
||||
ItemStack banner = new ItemStack(event.getItem());
|
||||
banner.setAmount(1);
|
||||
player.getInventory().removeItem(banner);
|
||||
if (player.getEquipment().getHelmet() != null) {
|
||||
if (player.getInventory().addItem(player.getEquipment().getHelmet()).size() != 0) {
|
||||
player.getWorld().dropItem(player.getLocation(), player.getEquipment().getHelmet());
|
||||
}
|
||||
}
|
||||
player.getEquipment().setHelmet(banner);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void tradeWanderer(PlayerInteractEntityEvent event) {
|
||||
if (!disableWanderingTrader) {
|
||||
return;
|
||||
}
|
||||
if (event.getRightClicked().getType() == EntityType.WANDERING_TRADER) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onTeleport(PlayerTeleportEvent event) {
|
||||
if (!preventPearlGlitching || event.getCause() != TeleportCause.ENDER_PEARL) {
|
||||
return;
|
||||
}
|
||||
Location to = event.getTo();
|
||||
|
||||
// From and To are feet positions. Check and make sure we can teleport to a
|
||||
// location with air
|
||||
// above the To location.
|
||||
Block toBlock = to.getBlock();
|
||||
Block aboveBlock = toBlock.getRelative(BlockFace.UP);
|
||||
Block belowBlock = toBlock.getRelative(BlockFace.DOWN);
|
||||
boolean lowerBlockBypass = false;
|
||||
double height = 0.0;
|
||||
Material mat = toBlock.getType();
|
||||
if (Tag.SLABS.isTagged(mat)) {
|
||||
lowerBlockBypass = true;
|
||||
height = 0.5;
|
||||
}
|
||||
else if (Tag.BEDS.isTagged(mat)) {
|
||||
height = 0.562;
|
||||
}
|
||||
else if (Tag.FLOWER_POTS.isTagged(mat)) {
|
||||
height = 0.375;
|
||||
}
|
||||
else switch (mat) {
|
||||
case CHEST:
|
||||
case TRAPPED_CHEST:
|
||||
case ENDER_CHEST:
|
||||
height = 0.875;
|
||||
break;
|
||||
case LILY_PAD:
|
||||
height = 0.016;
|
||||
break;
|
||||
case ENCHANTING_TABLE:
|
||||
height = 0.016;
|
||||
break;
|
||||
case PLAYER_WALL_HEAD:
|
||||
case PLAYER_HEAD:
|
||||
height = 0.5;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the below block is difficult
|
||||
// This is added because if you face downward directly on a gate, it will
|
||||
// teleport your feet INTO the gate, thus bypassing the gate until you leave
|
||||
// that block.
|
||||
Material belowMat = belowBlock.getType();
|
||||
if (Tag.FENCE_GATES.isTagged(belowMat) || Tag.FENCES.isTagged(belowMat) || Tag.WALLS.isTagged(belowMat)) {
|
||||
height = 0.5;
|
||||
}
|
||||
|
||||
boolean upperBlockBypass = false;
|
||||
if (height >= 0.5) {
|
||||
Block aboveHeadBlock = aboveBlock.getRelative(BlockFace.UP);
|
||||
if (!aboveHeadBlock.getType().isSolid()) {
|
||||
height = 0.5;
|
||||
} else {
|
||||
upperBlockBypass = true; // Cancel this event. What's happening is the user is going to get stuck due to
|
||||
// the height.
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize teleport to the center of the block. Feet ON the ground, plz.
|
||||
// Leave Yaw and Pitch alone
|
||||
to.setX(Math.floor(to.getX()) + 0.5);
|
||||
to.setY(Math.floor(to.getY()) + height);
|
||||
to.setZ(Math.floor(to.getZ()) + 0.5);
|
||||
|
||||
if (aboveBlock.getType().isSolid() || (toBlock.getType().isSolid() && !lowerBlockBypass) || upperBlockBypass) {
|
||||
boolean bypass = false;
|
||||
if ((to.getWorld().getEnvironment() == Environment.NETHER) && (to.getBlockY() > 124) && (to.getBlockY() < 129)) {
|
||||
bypass = true;
|
||||
}
|
||||
if (!bypass) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
|
||||
public void throwEyeOfEnder(PlayerInteractEvent pie) {
|
||||
if (!preventUsingEyeOfEnder) {
|
||||
return;
|
||||
}
|
||||
if (pie.getAction() != Action.RIGHT_CLICK_AIR && pie.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
if (pie.getItem() != null && pie.getItem().getType() == Material.ENDER_EYE) {
|
||||
pie.setCancelled(true);
|
||||
pie.getPlayer().sendMessage(ChatColor.RED + "Throwing Eyes of Ender is disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void lavaToCobble(BlockPhysicsEvent e) {
|
||||
if (!disableLavaCobbleMountains) {
|
||||
return;
|
||||
}
|
||||
if (e.getBlock().getType() != Material.LAVA) {
|
||||
return;
|
||||
}
|
||||
if (isLavaSourceNear(e.getBlock(), 3)) {
|
||||
return;
|
||||
}
|
||||
boolean foundWater = false;
|
||||
for (Block block : WorldUtils.getAllBlockSides(e.getBlock(), true)) {
|
||||
if (block.getType() == Material.WATER) {
|
||||
foundWater = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundWater) {
|
||||
Bukkit.getScheduler().runTask(SimpleAdminHacks.instance(), () -> e.getBlock().setType(Material.AIR));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isLavaSourceNear(Block block, int ttl) {
|
||||
if (ttl <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (block.getType() != Material.LAVA) {
|
||||
return false;
|
||||
}
|
||||
if (((Levelled) block.getBlockData()).getLevel() == 0) {
|
||||
// source block
|
||||
return true;
|
||||
}
|
||||
for (Block relative : WorldUtils.getAllBlockSides(block, true)) {
|
||||
if (isLavaSourceNear(relative, ttl - 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onBartering(EntitySpawnEvent event) {
|
||||
if (disablePiglins && event.getEntityType() == EntityType.PIGLIN) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import vg.civcraft.mc.civmodcore.chat.ChatUtils;
|
||||
|
||||
public class ItemMetaConverterHack extends BasicHack {
|
||||
|
||||
public ItemMetaConverterHack(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void convertOnInventoryOpen(final InventoryOpenEvent event) {
|
||||
final var inventory = event.getInventory();
|
||||
if (inventory.getHolder() == null) {
|
||||
return; // GUI
|
||||
}
|
||||
for (final ItemStack item : inventory.getStorageContents()) {
|
||||
processItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static void processItem(final ItemStack item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
final var meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
boolean displayNameWasChanged = false;
|
||||
if (meta.hasDisplayName()) {
|
||||
final var currentDisplayName = meta.displayName();
|
||||
assert currentDisplayName != null;
|
||||
if (!ChatUtils.isBaseComponent(currentDisplayName)) {
|
||||
meta.displayName(Component.text().append(currentDisplayName).build());
|
||||
displayNameWasChanged = true;
|
||||
}
|
||||
}
|
||||
boolean loreWasChanged = false;
|
||||
if (meta.hasLore()) {
|
||||
final var currentLore = meta.lore();
|
||||
assert currentLore != null;
|
||||
for (int i = 0, l = currentLore.size(); i < l; i++) {
|
||||
final var loreLine = currentLore.get(i);
|
||||
if (!ChatUtils.isBaseComponent(loreLine)) {
|
||||
currentLore.set(i, Component.text().append(loreLine).build());
|
||||
loreWasChanged = true;
|
||||
}
|
||||
}
|
||||
if (loreWasChanged) {
|
||||
meta.lore(currentLore);
|
||||
}
|
||||
}
|
||||
if (displayNameWasChanged || loreWasChanged) {
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.DataParser;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import vg.civcraft.mc.civmodcore.entities.EntityUtils;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.SpawnEggUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class MobCondenser extends BasicHack
|
||||
{
|
||||
private Random rng;
|
||||
private Map<EntityType, Double> mobSpawnModifiers;
|
||||
|
||||
@AutoLoad(processor = DataParser.MATERIAL)
|
||||
private List<Material> materialModificationWhitelist;
|
||||
|
||||
public MobCondenser(SimpleAdminHacks plugin, BasicHackConfig config)
|
||||
{
|
||||
super(plugin, config);
|
||||
this.rng = new Random();
|
||||
this.mobSpawnModifiers = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable()
|
||||
{
|
||||
super.onEnable();
|
||||
|
||||
final ConfigurationSection base = this.config.getBase();
|
||||
final ConfigurationSection spawnModifiers = base.getConfigurationSection("mobSpawnModifiers");
|
||||
if (spawnModifiers != null) {
|
||||
for (final String key : spawnModifiers.getKeys(false)) {
|
||||
final EntityType type = EntityUtils.getEntityType(key);
|
||||
if (type == null) {
|
||||
this.plugin.warning("[" + getClass().getSimpleName() + "] EntityType: \"" + key + "\" does not exist, skipping.");
|
||||
continue;
|
||||
}
|
||||
double modifier = spawnModifiers.getDouble(key, 1.0d);
|
||||
if (modifier < 0.0d) {
|
||||
this.plugin.warning("[" + getClass().getSimpleName() + "] Mob Spawn Modifier: \"" + modifier + "\" for \"" + key + "\" is unsupported, defaulting to 1.0");
|
||||
modifier = 1.0d;
|
||||
}
|
||||
this.mobSpawnModifiers.put(type, modifier);
|
||||
this.plugin.info("[" + getClass().getSimpleName() + "] Registered Mob Spawn Modifier: [" + type + ": " + modifier + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable()
|
||||
{
|
||||
this.mobSpawnModifiers.clear();
|
||||
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
private boolean roll(double chance) {
|
||||
return rng.nextDouble() <= chance;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW) //Run before the PortalSpawnModifier
|
||||
public void onCreatureSpawn(CreatureSpawnEvent e) {
|
||||
if (mobSpawnModifiers.containsKey(e.getEntityType())) {
|
||||
if (!roll(mobSpawnModifiers.get(e.getEntityType()))) {
|
||||
if (e.getSpawnReason() != CreatureSpawnEvent.SpawnReason.SPAWNER_EGG) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
else if (e.getEntity() instanceof Ageable) // Is from a spawn egg, and is Ageable
|
||||
{
|
||||
Ageable ageable = (Ageable) e.getEntity();
|
||||
|
||||
if (!ageable.isAdult()) { //Only spawns from right clicking other mobs with a spawn egg
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onMobEggUse(PlayerInteractEvent e) {
|
||||
if (e.getAction() == Action.RIGHT_CLICK_BLOCK && e.getItem() != null) {
|
||||
try {
|
||||
EntityType type = SpawnEggUtils.getEntityType(e.getItem().getType());
|
||||
|
||||
if (mobSpawnModifiers.containsKey(type)) {
|
||||
if (!roll(mobSpawnModifiers.get(type))) {
|
||||
e.setCancelled(true);
|
||||
e.getItem().setAmount(e.getItem().getAmount() -1);
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH) //Run after PortalSpawnModifier
|
||||
public void onEntityDeath(EntityDeathEvent e) {
|
||||
if (mobSpawnModifiers.containsKey(e.getEntityType())) {
|
||||
Iterator<ItemStack> iterator = e.getDrops().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ItemStack itemStack = iterator.next();
|
||||
if (materialModificationWhitelist.contains(itemStack.getType())) {
|
||||
itemStack.setAmount((int) Math.round(itemStack.getAmount() / mobSpawnModifiers.get(e.getEntityType())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+657
@@ -0,0 +1,657 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.PacketManager;
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Level;
|
||||
import net.minecraft.world.inventory.EnchantmentMenu;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftInventoryView;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.ThrownExpBottle;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockExpEvent;
|
||||
import org.bukkit.event.enchantment.EnchantItemEvent;
|
||||
import org.bukkit.event.enchantment.PrepareItemEnchantEvent;
|
||||
import org.bukkit.event.entity.EntityBreedEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.ExpBottleEvent;
|
||||
import org.bukkit.event.inventory.FurnaceExtractEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryCreativeEvent;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.inventory.PrepareAnvilEvent;
|
||||
import org.bukkit.event.player.PlayerExpChangeEvent;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.AnvilInventory;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.Merchant;
|
||||
import org.bukkit.inventory.MerchantRecipe;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.inventory.ShapedRecipe;
|
||||
import org.bukkit.inventory.ShapelessRecipe;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.Repairable;
|
||||
import org.bukkit.projectiles.ProjectileSource;
|
||||
import vg.civcraft.mc.civmodcore.entities.EntityUtils;
|
||||
import vg.civcraft.mc.civmodcore.inventory.InventoryUtils;
|
||||
import vg.civcraft.mc.civmodcore.inventory.RecipeManager;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.ItemMap;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;
|
||||
import vg.civcraft.mc.civmodcore.world.WorldUtils;
|
||||
|
||||
public final class OldEnchanting extends BasicHack {
|
||||
|
||||
private static final ItemStack LAPIS_ITEM = new ItemStack(Material.LAPIS_LAZULI, 64);
|
||||
private static final ItemStack EMERALD_ITEM = new ItemStack(Material.EMERALD, 1);
|
||||
private static final Random RANDOM = new SecureRandom();
|
||||
|
||||
private final PacketManager packets;
|
||||
private final ShapelessRecipe emeraldToExp;
|
||||
private final ShapedRecipe expToEmerald;
|
||||
private final Field enchantingTableRandomiser;
|
||||
private final Map<EntityType, Double> entityExpDropModifiers;
|
||||
|
||||
@AutoLoad
|
||||
private boolean hideEnchants;
|
||||
|
||||
@AutoLoad
|
||||
private boolean fillLapis;
|
||||
|
||||
@AutoLoad
|
||||
private boolean randomiseEnchants;
|
||||
|
||||
@AutoLoad
|
||||
private boolean fixEnchantCosts;
|
||||
|
||||
@AutoLoad
|
||||
private double experienceModifier;
|
||||
|
||||
@AutoLoad
|
||||
private double lootModifier;
|
||||
|
||||
@AutoLoad
|
||||
private boolean emeraldCrafting;
|
||||
|
||||
@AutoLoad
|
||||
private boolean emeraldLeveling;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableGrindExp;
|
||||
|
||||
@AutoLoad
|
||||
private boolean preventOrbExp;
|
||||
|
||||
@AutoLoad
|
||||
private boolean directBottleExp;
|
||||
|
||||
@AutoLoad
|
||||
private int maxRepairCost;
|
||||
|
||||
@AutoLoad
|
||||
private int expPerBottle;
|
||||
|
||||
@AutoLoad
|
||||
private boolean allowExpRecovery;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableEnchantedBookCreation;
|
||||
|
||||
@AutoLoad
|
||||
private boolean disableEnchantedBookUsage;
|
||||
|
||||
public OldEnchanting(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
// Setup packet manager
|
||||
this.packets = new PacketManager();
|
||||
// Recipe that crafts Bottles o' Enchanting from Emeralds
|
||||
this.emeraldToExp = new ShapelessRecipe(
|
||||
new NamespacedKey(plugin, "emeraldToBottle"),
|
||||
new ItemStack(Material.EXPERIENCE_BOTTLE, 9));
|
||||
this.emeraldToExp.addIngredient(Material.EMERALD);
|
||||
// Recipe that crafts Emeralds from Bottles o' Enchanting
|
||||
this.expToEmerald = new ShapedRecipe(
|
||||
new NamespacedKey(plugin, "bottleToEmerald"),
|
||||
EMERALD_ITEM);
|
||||
this.expToEmerald.shape("xxx", "xxx", "xxx");
|
||||
this.expToEmerald.setIngredient('x', Material.EXPERIENCE_BOTTLE);
|
||||
// Setup enchantment randomiser
|
||||
Field randomiser = null;
|
||||
try {
|
||||
randomiser = FieldUtils.getDeclaredField(EnchantmentMenu.class, "h", true);
|
||||
}
|
||||
catch (final Throwable throwable) {
|
||||
this.logger.log(Level.WARNING, "An exception was thrown while trying to reflect the enchanting " +
|
||||
"table's randomiser field.", throwable);
|
||||
}
|
||||
this.enchantingTableRandomiser = randomiser;
|
||||
// Setup entity xp modifiers
|
||||
this.entityExpDropModifiers = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
if (this.experienceModifier < 0.0d) {
|
||||
this.logger.warning("[OldEnchanting] Experience modifier [" + this.experienceModifier + "] " +
|
||||
"is unsupported, defaulting to 0.2");
|
||||
this.experienceModifier = 0.2d;
|
||||
}
|
||||
if (this.lootModifier < 0.0d) {
|
||||
this.logger.warning("[OldEnchanting] Loot modifier [" + this.lootModifier + "] " +
|
||||
"is unsupported, defaulting to 1.5");
|
||||
this.lootModifier = 1.5d;
|
||||
}
|
||||
if (this.maxRepairCost < 2 && this.maxRepairCost != -1) {
|
||||
this.logger.warning("[OldEnchanting] Maximum repair cost [" + this.maxRepairCost + "] " +
|
||||
"is unsupported, defaulting to 33");
|
||||
this.maxRepairCost = 33;
|
||||
}
|
||||
if (this.expPerBottle < -1) {
|
||||
this.logger.warning("[OldEnchanting] Experience per bottle [" + this.expPerBottle + "] " +
|
||||
"is unsupported, defaulting to 10");
|
||||
this.expPerBottle = 10;
|
||||
}
|
||||
{ // @AutoLoad is not sophisticated enough to handle maps
|
||||
final ConfigurationSection base = this.config.getBase();
|
||||
final ConfigurationSection modifiers = base.getConfigurationSection("entityExpDropModifiers");
|
||||
if (modifiers != null) {
|
||||
for (final String key : modifiers.getKeys(false)) {
|
||||
final EntityType type = EntityUtils.getEntityType(key);
|
||||
if (type == null) {
|
||||
this.logger.warning("[OldEnchanting] EntityType [" + key + "] does not exist, skipping.");
|
||||
continue;
|
||||
}
|
||||
double modifier = modifiers.getDouble(key, 1.0d);
|
||||
if (modifier < 0.0d) {
|
||||
this.logger.warning("[OldEnchanting] Experience modifier [" + modifier + "] for " +
|
||||
"[" + key + "] is unsupported, defaulting to 1.0");
|
||||
modifier = 1.0d;
|
||||
}
|
||||
this.entityExpDropModifiers.put(type, modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.hideEnchants) {
|
||||
this.packets.addAdapter(new PacketAdapter(this.plugin, PacketType.Play.Server.WINDOW_DATA) {
|
||||
@Override
|
||||
public void onPacketSending(final PacketEvent event) {
|
||||
final InventoryType type = event.getPlayer().getOpenInventory().getType();
|
||||
if (type == InventoryType.ENCHANTING) {
|
||||
final PacketContainer packet = event.getPacket();
|
||||
final int property = packet.getIntegers().read(1);
|
||||
switch (property) {
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
packet.getIntegers().write(2, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.emeraldCrafting) {
|
||||
RecipeManager.registerRecipe(this.emeraldToExp);
|
||||
RecipeManager.registerRecipe(this.expToEmerald);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (this.fillLapis) {
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
final InventoryView inventory = player.getOpenInventory();
|
||||
if (inventory.getType() != InventoryType.ENCHANTING) {
|
||||
continue;
|
||||
}
|
||||
inventory.setItem(1, null);
|
||||
}
|
||||
}
|
||||
this.entityExpDropModifiers.clear();
|
||||
this.packets.removeAllAdapters();
|
||||
if (this.emeraldCrafting) {
|
||||
RecipeManager.removeRecipe(this.emeraldToExp);
|
||||
RecipeManager.removeRecipe(this.expToEmerald);
|
||||
}
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onEntityDeath(final EntityDeathEvent event) {
|
||||
if (this.disableGrindExp) {
|
||||
event.setDroppedExp(0);
|
||||
return;
|
||||
}
|
||||
final LivingEntity entity = event.getEntity();
|
||||
final EntityType entityType = entity.getType();
|
||||
int experience = event.getDroppedExp();
|
||||
if (this.entityExpDropModifiers.containsKey(entityType)) {
|
||||
experience = applyModifier(experience, this.entityExpDropModifiers.get(entityType));
|
||||
}
|
||||
else if (entityType != EntityType.PLAYER) {
|
||||
experience = applyModifier(experience, this.experienceModifier);
|
||||
}
|
||||
if (entityType != EntityType.PLAYER) {
|
||||
final Player killer = entity.getKiller();
|
||||
if (killer != null) {
|
||||
final ItemStack held = killer.getInventory().getItemInMainHand();
|
||||
if (ItemUtils.isValidItem(held) && held.hasItemMeta()) {
|
||||
final ItemMeta meta = held.getItemMeta();
|
||||
if (meta.hasEnchant(Enchantment.LOOT_BONUS_MOBS)) {
|
||||
final double modifier = this.lootModifier * meta.getEnchantLevel(Enchantment.LOOT_BONUS_MOBS);
|
||||
experience = applyModifier(experience, modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
event.setDroppedExp(Math.max(0, experience));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onBlockExp(final BlockExpEvent event) {
|
||||
if (this.disableGrindExp) {
|
||||
event.setExpToDrop(0);
|
||||
}
|
||||
else {
|
||||
event.setExpToDrop(applyModifier(event.getExpToDrop(), this.experienceModifier));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onFurnaceExp(final FurnaceExtractEvent event) {
|
||||
if (this.disableGrindExp) {
|
||||
event.setExpToDrop(0);
|
||||
}
|
||||
else {
|
||||
event.setExpToDrop(applyModifier(event.getExpToDrop(), this.experienceModifier));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onFishingExp(final PlayerFishEvent event) {
|
||||
if (this.disableGrindExp) {
|
||||
event.setExpToDrop(0);
|
||||
}
|
||||
else {
|
||||
event.setExpToDrop(applyModifier(event.getExpToDrop(), this.experienceModifier));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onBreedExp(final EntityBreedEvent event) {
|
||||
if (this.disableGrindExp) {
|
||||
event.setExperience(0);
|
||||
}
|
||||
else {
|
||||
event.setExperience(applyModifier(event.getExperience(), this.experienceModifier));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onMerchantRecipe(final InventoryOpenEvent event) {
|
||||
if (!this.disableGrindExp) {
|
||||
return;
|
||||
}
|
||||
final Inventory inventory = event.getInventory();
|
||||
if (!(inventory instanceof Merchant)) {
|
||||
return;
|
||||
}
|
||||
for (final MerchantRecipe recipe : ((Merchant) inventory).getRecipes()) {
|
||||
recipe.setExperienceReward(false);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onExpChange(final PlayerExpChangeEvent event) {
|
||||
if (this.preventOrbExp) {
|
||||
event.setAmount(0);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onExpBottle(final ExpBottleEvent event) {
|
||||
if (this.expPerBottle != -1) { // If bottle xp is not random
|
||||
event.setExperience(this.expPerBottle);
|
||||
}
|
||||
if (this.directBottleExp) {
|
||||
final ThrownExpBottle bottle = event.getEntity();
|
||||
final ProjectileSource thrower = bottle.getShooter();
|
||||
if (thrower instanceof Player) {
|
||||
final Player player = (Player) thrower;
|
||||
player.giveExp(event.getExperience());
|
||||
// Play the experience sound as no experience orbs will be spawned
|
||||
// Credit to Team CoFH for the random pitch generator, see their code below
|
||||
// https://github.com/CoFH/ThermalFoundation/blob/1.12/src/main/java/cofh/thermalfoundation/item/tome/ItemTomeExperience.java#L268
|
||||
// This is a reasonable use of their "Copy portions of this code for use in other projects." clause.
|
||||
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.1F,
|
||||
(RANDOM.nextFloat() - RANDOM.nextFloat()) * 0.35f + 0.9f);
|
||||
event.setExperience(0);
|
||||
bottle.teleport(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onEmeraldExp(final PlayerInteractEvent event) {
|
||||
if (!this.emeraldCrafting
|
||||
|| !this.emeraldLeveling
|
||||
|| this.expPerBottle == 0) {
|
||||
return;
|
||||
}
|
||||
switch (event.getAction()) {
|
||||
case RIGHT_CLICK_AIR:
|
||||
case RIGHT_CLICK_BLOCK:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
final PlayerInventory inventory = player.getInventory();
|
||||
final EquipmentSlot slot = Objects.requireNonNull(event.getHand());
|
||||
final ItemStack held = inventory.getItem(slot);
|
||||
if (!ItemUtils.isValidItem(held)
|
||||
|| !ItemUtils.areItemsSimilar(held, EMERALD_ITEM)) {
|
||||
return;
|
||||
}
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
final Block clicked = Objects.requireNonNull(event.getClickedBlock());
|
||||
if (clicked.getType().isInteractable()) {
|
||||
event.setCancelled(true); // Don't give levels if trying to open a chest for example
|
||||
return;
|
||||
}
|
||||
}
|
||||
final int amount = held.getAmount();
|
||||
if (amount <= 0) {
|
||||
return;
|
||||
}
|
||||
int experience = 0;
|
||||
if (this.expPerBottle != -1) { // If bottle xp is not random
|
||||
experience = this.expPerBottle * 9;
|
||||
}
|
||||
else {
|
||||
// Simulate nine thrown bottles, which drop between 3-11 experience
|
||||
// https://minecraft.gamepedia.com/Bottle_o%27_Enchanting
|
||||
for (int i = 0; i < 9; i++) {
|
||||
experience += RANDOM.nextInt(11 - 3 + 1) + 3;
|
||||
}
|
||||
}
|
||||
player.giveExp(experience);
|
||||
inventory.setItem(slot, ItemUtils.decrementItem(held));
|
||||
event.setCancelled(true); // Give the emerald leveling precedence
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerExpRecovery(final PlayerInteractEvent event) {
|
||||
if (!this.allowExpRecovery
|
||||
|| this.expPerBottle == -1 // If bottle xp is random
|
||||
|| this.expPerBottle == 0 // If bottle xp is nothing
|
||||
|| event.getAction() != Action.LEFT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
final Block block = event.getClickedBlock();
|
||||
if (!WorldUtils.isValidBlock(block)
|
||||
|| block.getType() != Material.ENCHANTING_TABLE) {
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
final PlayerInventory inventory = player.getInventory();
|
||||
final ItemStack held = inventory.getItemInMainHand();
|
||||
if (held.getType() != Material.GLASS_BOTTLE) {
|
||||
return;
|
||||
}
|
||||
final int totalExp = computeCurrentXP(player);
|
||||
if (totalExp < this.expPerBottle) {
|
||||
return;
|
||||
}
|
||||
createExpBottles(player, totalExp);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPrepareBookEnchant(final PrepareItemEnchantEvent event) {
|
||||
if (!this.disableEnchantedBookCreation) {
|
||||
return;
|
||||
}
|
||||
final ItemStack item = event.getItem();
|
||||
if (!ItemUtils.isValidItem(item)
|
||||
|| item.getType() != Material.BOOK) {
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPrepareBookUsage(final PrepareAnvilEvent event) {
|
||||
if (!this.disableEnchantedBookUsage) {
|
||||
return;
|
||||
}
|
||||
final AnvilInventory inventory = event.getInventory();
|
||||
if (inventory.first(Material.ENCHANTED_BOOK) != -1) {
|
||||
if (event.getResult() != null) {
|
||||
event.setResult(null);
|
||||
// This is needed because of client side shenanigans
|
||||
Bukkit.getScheduler().runTaskLater(this.plugin, () -> {
|
||||
for (final Player viewer : InventoryUtils.getViewingPlayers(inventory)) {
|
||||
viewer.updateInventory();
|
||||
}
|
||||
}, 1L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPrepareItemEnchant(final PrepareItemEnchantEvent event) {
|
||||
final CraftInventoryView view = (CraftInventoryView) event.getView();
|
||||
final EnchantmentMenu table = (EnchantmentMenu) view.getHandle();
|
||||
if (this.randomiseEnchants) {
|
||||
try {
|
||||
final Random tableRandom = (Random) this.enchantingTableRandomiser.get(table);
|
||||
tableRandom.nextDouble();
|
||||
}
|
||||
catch (final IllegalArgumentException | IllegalAccessException | ClassCastException throwable) {
|
||||
this.logger.log(Level.WARNING, "Could not set randomiser!", throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onAnvilRepair(final PrepareAnvilEvent event) {
|
||||
if (this.maxRepairCost == -1) { // If no maximum
|
||||
return;
|
||||
}
|
||||
final ItemStack result = event.getResult();
|
||||
if (!ItemUtils.isValidItem(result)) {
|
||||
return;
|
||||
}
|
||||
ItemUtils.handleItemMeta(result, (Repairable meta) -> {
|
||||
final int newRepairCost = this.maxRepairCost - 2;
|
||||
if (meta.getRepairCost() < newRepairCost) {
|
||||
return false;
|
||||
}
|
||||
meta.setRepairCost(newRepairCost);
|
||||
return true;
|
||||
});
|
||||
event.setResult(result);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onEnchantItem(final EnchantItemEvent event) {
|
||||
if (this.fixEnchantCosts) {
|
||||
final Player player = event.getEnchanter();
|
||||
if (player.getLevel() < event.getExpLevelCost()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
// The level cost of enchantments is always the button index + 1, assuming the server is Bukkit.
|
||||
// And so if we want the enchantment to actually cost 30 levels as required by the ExpLevelCost, we need to
|
||||
// make up for the difference with a manual level reduction of the remainder.
|
||||
final int bukkitLevelCost = event.whichButton() + 1;
|
||||
final int levelRemainder = event.getExpLevelCost() - bukkitLevelCost;
|
||||
final int newLevel = player.getLevel() - levelRemainder;
|
||||
player.setLevel(newLevel);
|
||||
// The exp level cost needs to be reduced to the remaining cost, otherwise Bukkit's enchantment process
|
||||
// still expects you to have thirty levels on you.
|
||||
event.setExpLevelCost(bukkitLevelCost);
|
||||
}
|
||||
if (this.fillLapis) {
|
||||
event.getInventory().setItem(1, LAPIS_ITEM.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This function causes weirdness when you place Lapis Lazuli in the item to enchant slot. It should be
|
||||
// modified to only cancel the event if items are being added to or removed from the consumable slot.
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onInventoryClick(final InventoryClickEvent event) {
|
||||
if (!this.fillLapis
|
||||
|| event instanceof InventoryCreativeEvent) {
|
||||
return;
|
||||
}
|
||||
final Inventory inventory = event.getClickedInventory();
|
||||
if (!InventoryUtils.isValidInventory(inventory) || inventory.getType() != InventoryType.ENCHANTING) {
|
||||
return;
|
||||
}
|
||||
final ItemStack currentItem = event.getCurrentItem();
|
||||
if (!ItemUtils.isValidItem(currentItem) || !currentItem.isSimilar(LAPIS_ITEM)) {
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onOpenEnchantingTable(final InventoryOpenEvent event) {
|
||||
if (!this.fillLapis) {
|
||||
return;
|
||||
}
|
||||
final Inventory inventory = event.getInventory();
|
||||
if (inventory.getType() != InventoryType.ENCHANTING) {
|
||||
return;
|
||||
}
|
||||
event.getInventory().setItem(1, LAPIS_ITEM.clone());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onCloseEnchantingTable(final InventoryCloseEvent event) {
|
||||
if (!this.fillLapis) {
|
||||
return;
|
||||
}
|
||||
final Inventory inventory = event.getInventory();
|
||||
if (inventory.getType() != InventoryType.ENCHANTING) {
|
||||
return;
|
||||
}
|
||||
inventory.setItem(1, null);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onBreakEnchantingTable(final BlockBreakEvent event) {
|
||||
if (!this.fillLapis) {
|
||||
return;
|
||||
}
|
||||
final Block block = event.getBlock();
|
||||
if (block.getType() != Material.ENCHANTING_TABLE) {
|
||||
return;
|
||||
}
|
||||
block.getDrops().removeIf(drop -> drop.isSimilar(LAPIS_ITEM));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Do not touch anything below unless you want a headache!
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private int applyModifier(int experience, double modifier) {
|
||||
return (int) Math.max(0, Math.ceil(experience * modifier));
|
||||
}
|
||||
|
||||
private int computeCurrentXP(Player player) {
|
||||
float currentLevel = player.getLevel();
|
||||
float progress = player.getExp();
|
||||
float a = 1f, b = 6f, c = 0f, x = 2f, y = 7f;
|
||||
if (currentLevel > 16 && currentLevel <= 31) {
|
||||
a = 2.5f;
|
||||
b = -40.5f;
|
||||
c = 360f;
|
||||
x = 5f;
|
||||
y = -38f;
|
||||
}
|
||||
else if (currentLevel >= 32) {
|
||||
a = 4.5f;
|
||||
b = -162.5f;
|
||||
c = 2220f;
|
||||
x = 9f;
|
||||
y = -158f;
|
||||
}
|
||||
return (int) Math
|
||||
.floor(a * currentLevel * currentLevel + b * currentLevel + c + progress * (x * currentLevel + y));
|
||||
}
|
||||
|
||||
private void createExpBottles(Player player, int totalExp) {
|
||||
ItemMap inv = new ItemMap(player.getInventory());
|
||||
int bottles = inv.getAmount(new ItemStack(Material.GLASS_BOTTLE));
|
||||
int xpavailable = totalExp / this.expPerBottle;
|
||||
int remove = Math.min(bottles, xpavailable);
|
||||
if (remove == 0) {
|
||||
return;
|
||||
}
|
||||
boolean noSpace = false;
|
||||
int bottleCount = 0;
|
||||
ItemMap removeMap = new ItemMap();
|
||||
removeMap.addItemAmount(new ItemStack(Material.GLASS_BOTTLE), remove);
|
||||
for (ItemStack is : removeMap.getItemStackRepresentation()) {
|
||||
int initialAmount = is.getAmount();
|
||||
player.getInventory().removeItem(is);
|
||||
is.setType(Material.EXPERIENCE_BOTTLE);
|
||||
HashMap<Integer, ItemStack> result = player.getInventory().addItem(is);
|
||||
if (!result.isEmpty()) {
|
||||
is.setType(Material.GLASS_BOTTLE);
|
||||
player.getInventory().addItem(is);
|
||||
noSpace = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
bottleCount += initialAmount;
|
||||
}
|
||||
}
|
||||
if (bottleCount > 0) {
|
||||
int endXP = totalExp - bottleCount * this.expPerBottle;
|
||||
player.setLevel(0);
|
||||
player.setExp(0);
|
||||
player.giveExp(endXP);
|
||||
player.sendMessage(ChatColor.GREEN + "Created " + bottleCount + " XP bottles.");
|
||||
}
|
||||
if (noSpace) {
|
||||
player.sendMessage(ChatColor.RED + "Not enough space in inventory for all XP bottles.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Phantom;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.player.PlayerStatisticIncrementEvent;
|
||||
import vg.civcraft.mc.civmodcore.world.WorldUtils;
|
||||
|
||||
public final class PhantomMenace extends BasicHack {
|
||||
|
||||
@AutoLoad
|
||||
private int timeSinceRestCap;
|
||||
|
||||
@AutoLoad
|
||||
private boolean nightSpawn;
|
||||
|
||||
@AutoLoad
|
||||
private boolean stormSpawn;
|
||||
|
||||
@AutoLoad
|
||||
private int maximumLightSpawn;
|
||||
|
||||
public PhantomMenace(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.timeSinceRestCap = Math.max(-1, this.timeSinceRestCap);
|
||||
this.maximumLightSpawn = Math.min(Math.max(this.maximumLightSpawn, 0), 15);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCreatureSpawn(final CreatureSpawnEvent event) {
|
||||
// Do not regulate unless the creature is a phantom
|
||||
if (event.getEntityType() != EntityType.PHANTOM) {
|
||||
return;
|
||||
}
|
||||
// Do not regulate phantom spawning unless it's natural
|
||||
switch (event.getSpawnReason()) {
|
||||
case NATURAL:
|
||||
case DEFAULT:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (!this.nightSpawn && !this.stormSpawn) {
|
||||
event.setCancelled(true);
|
||||
plugin().debug("Phantom prevented from spawning: cannot spawn during the night nor during storms.");
|
||||
return;
|
||||
}
|
||||
final Phantom phantom = (Phantom) event.getEntity();
|
||||
final World world = phantom.getWorld();
|
||||
if (!this.nightSpawn && this.stormSpawn) {
|
||||
if (!world.hasStorm()) {
|
||||
event.setCancelled(true);
|
||||
plugin().debug("Phantom prevented from spawning: night spawning disabled.");
|
||||
}
|
||||
}
|
||||
else if (this.nightSpawn && !this.stormSpawn) {
|
||||
if (world.getTime() < 12300 || world.getTime() > 23850) {
|
||||
event.setCancelled(true);
|
||||
plugin().debug("Phantom prevented from spawning: storm spawning disabled.");
|
||||
}
|
||||
}
|
||||
final UUID targetUUID = phantom.getSpawningEntity();
|
||||
if (targetUUID != null) {
|
||||
final Entity target = Bukkit.getEntity(targetUUID);
|
||||
if (target != null) {
|
||||
final Location targetLocation = target.getLocation();
|
||||
if (WorldUtils.isBlockLoaded(targetLocation)) {
|
||||
final Block targetBlock = targetLocation.getBlock();
|
||||
final int lightLevel = targetBlock.getLightLevel();
|
||||
if (lightLevel > this.maximumLightSpawn) {
|
||||
event.setCancelled(true);
|
||||
plugin().debug("Phantom prevented from spawning: light level was too high.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Otherwise let the phantom(s) spawn
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onStatisticIncrease(final PlayerStatisticIncrementEvent event) {
|
||||
if (event.getStatistic() != Statistic.TIME_SINCE_REST) {
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
if (event.getPreviousValue() < 72_000 && event.getNewValue() >= 72_000) {
|
||||
player.sendMessage(ChatColor.DARK_RED + "You haven't slept in a while...");
|
||||
}
|
||||
final int cap = this.timeSinceRestCap;
|
||||
if (cap <= -1 || event.getNewValue() < cap) {
|
||||
return;
|
||||
}
|
||||
player.setStatistic(Statistic.TIME_SINCE_REST, Math.min(event.getNewValue(), cap));
|
||||
event.setCancelled(true); // Prevent the increment
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import vg.civcraft.mc.civmodcore.commands.CommandManager;
|
||||
|
||||
public final class PlayerRevive extends BasicHack {
|
||||
|
||||
private final CommandManager commands;
|
||||
|
||||
public PlayerRevive(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.commands = new CommandManager(plugin) {
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
registerCommand(new ReviveCommand());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
this.commands.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.commands.reset();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@CommandPermission("simpleadmin.revive")
|
||||
public static class ReviveCommand extends BaseCommand {
|
||||
|
||||
@CommandAlias("revive|respawn|resurrect|ress")
|
||||
@Syntax("<player name>")
|
||||
@Description("Revives a player")
|
||||
@CommandCompletion("@players")
|
||||
public void revivePlayer(final CommandSender sender, @Single final String name) {
|
||||
final Player player = Bukkit.getPlayer(name);
|
||||
if (player == null) {
|
||||
sender.sendMessage(ChatColor.RED + "That player doesn't exist or isn't online.");
|
||||
return;
|
||||
}
|
||||
if (!player.isDead()) {
|
||||
sender.sendMessage(ChatColor.RED + "That player is not dead.");
|
||||
return;
|
||||
}
|
||||
final Location prevBedSpawn = player.getBedSpawnLocation();
|
||||
player.setBedSpawnLocation(player.getLocation(), true);
|
||||
player.spigot().respawn();
|
||||
player.setBedSpawnLocation(prevBedSpawn, true);
|
||||
player.sendMessage(ChatColor.YELLOW + "You have been revived.");
|
||||
sender.sendMessage(player.getName() + " revived.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.BukkitCommandCompletionContext;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandCompletion;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Default;
|
||||
import co.aikar.commands.annotation.Description;
|
||||
import co.aikar.commands.annotation.Optional;
|
||||
import co.aikar.commands.annotation.Single;
|
||||
import co.aikar.commands.annotation.Syntax;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import vg.civcraft.mc.civmodcore.commands.CommandManager;
|
||||
import vg.civcraft.mc.civmodcore.commands.TabComplete;
|
||||
|
||||
public final class PlayerStatistics extends BasicHack {
|
||||
|
||||
private final CommandManager commands;
|
||||
|
||||
public PlayerStatistics(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
this.commands = new CommandManager(plugin()) {
|
||||
@Override
|
||||
public void registerCommands() {
|
||||
registerCommand(new StatsCommand());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
this.commands.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.commands.reset();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@CommandPermission("simpleadmin.stats")
|
||||
public static class StatsCommand extends BaseCommand {
|
||||
|
||||
public static final String ALIAS = "stats|stat|statistic|statistics";
|
||||
|
||||
@CommandAlias(StatsCommand.ALIAS)
|
||||
@Default
|
||||
public void fallback(final CommandSender sender, @Optional final String playerName) {
|
||||
sender.sendMessage(ChatColor.RED + "Available statistics commands:");
|
||||
sender.sendMessage(ChatColor.YELLOW + "get: " + ChatColor.WHITE + "/stats <player> <statistic>");
|
||||
sender.sendMessage(ChatColor.YELLOW + "set: " + ChatColor.WHITE + "/stats <player> <statistic> <value>");
|
||||
}
|
||||
|
||||
@CommandAlias(StatsCommand.ALIAS)
|
||||
@Description("Gets the statistic for a player.")
|
||||
@Syntax("<player> <statistic>")
|
||||
@CommandCompletion("@players @stats")
|
||||
public void getPlayerStatistic(final CommandSender sender,
|
||||
final String playerName,
|
||||
@Single final String statName) {
|
||||
final Player player = Bukkit.getPlayer(playerName);
|
||||
if (player == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Could not find that player.");
|
||||
return;
|
||||
}
|
||||
final Statistic statistic = EnumUtils.getEnumIgnoreCase(Statistic.class, statName);
|
||||
if (statistic == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Could not find that statistic.");
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(ChatColor.GOLD + player.getName() + " [" + statistic.name() + "]: " +
|
||||
ChatColor.WHITE + player.getStatistic(statistic));
|
||||
}
|
||||
|
||||
@CommandAlias(StatsCommand.ALIAS)
|
||||
@Description("Sets the statistic for a player.")
|
||||
@Syntax("<player> <statistic> <value>")
|
||||
@CommandCompletion("@players @stats @nothing")
|
||||
public void setPlayerStatistic(final CommandSender sender,
|
||||
final String playerName,
|
||||
final String statName,
|
||||
final int value) {
|
||||
final Player player = Bukkit.getPlayer(playerName);
|
||||
if (player == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Could not find that player.");
|
||||
return;
|
||||
}
|
||||
final Statistic statistic = EnumUtils.getEnumIgnoreCase(Statistic.class, statName);
|
||||
if (statistic == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Could not find that statistic.");
|
||||
return;
|
||||
}
|
||||
player.setStatistic(statistic, value);
|
||||
sender.sendMessage(ChatColor.GOLD + player.getName() + " [" + statistic.name() + "] set to: " +
|
||||
ChatColor.WHITE + player.getStatistic(statistic));
|
||||
}
|
||||
|
||||
@TabComplete("stats")
|
||||
public List<String> tabCompleteStatistics(final BukkitCommandCompletionContext context) {
|
||||
final List<String> results = new ArrayList<>();
|
||||
for (final Statistic statistic : Statistic.values()) {
|
||||
final String slug = statistic.name();
|
||||
if (!StringUtils.startsWith(slug, context.getInput())) {
|
||||
continue;
|
||||
}
|
||||
results.add(slug);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.PigZombie;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.block.BlockDispenseArmorEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PortalSpawnModifier extends BasicHack {
|
||||
|
||||
private Random rng;
|
||||
|
||||
@AutoLoad
|
||||
private double pigManChance;
|
||||
@AutoLoad
|
||||
private double ghastChance;
|
||||
@AutoLoad
|
||||
private double witherSkeletonChance;
|
||||
|
||||
@AutoLoad
|
||||
private double witherHeadDropChance;
|
||||
|
||||
public PortalSpawnModifier(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
rng = new Random();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void portalSpawn(CreatureSpawnEvent event) {
|
||||
if (event.getSpawnReason() != SpawnReason.NETHER_PORTAL) {
|
||||
return;
|
||||
}
|
||||
if (event.getEntityType() == EntityType.ZOMBIFIED_PIGLIN) {
|
||||
if (!roll(pigManChance)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (roll(ghastChance)) {
|
||||
event.setCancelled(true);
|
||||
spawnGhast(event.getLocation());
|
||||
}
|
||||
else if (roll(witherSkeletonChance)) {
|
||||
event.setCancelled(true);
|
||||
spawnWitherSkeleton(event.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnGhast(Location loc) {
|
||||
PigZombie pigZombie = (PigZombie) loc.getWorld().spawnEntity(loc, EntityType.ZOMBIFIED_PIGLIN);
|
||||
pigZombie.getEquipment().setItemInOffHand(new ItemStack(Material.GHAST_TEAR));
|
||||
}
|
||||
|
||||
private void spawnWitherSkeleton(Location loc) {
|
||||
PigZombie pigZombie = (PigZombie) loc.getWorld().spawnEntity(loc, EntityType.ZOMBIFIED_PIGLIN);
|
||||
pigZombie.getEquipment().setHelmet(new ItemStack(Material.WITHER_SKELETON_SKULL));
|
||||
}
|
||||
|
||||
private boolean roll(double chance) {
|
||||
return rng.nextDouble() <= chance;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityPickupItem(EntityPickupItemEvent e) {
|
||||
if (e.getEntityType() == EntityType.ZOMBIFIED_PIGLIN) {
|
||||
e.setCancelled(true); // Prevents giving piglins items to change what they drop
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void dispenseArmorEvent(BlockDispenseArmorEvent e) {
|
||||
if (e.getTargetEntity().getType() == EntityType.ZOMBIFIED_PIGLIN) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void zombiePiglinDeath(EntityDeathEvent e) {
|
||||
if (e.getEntityType() != EntityType.ZOMBIFIED_PIGLIN) { // If the death is not a piglin, we can disregard.
|
||||
return;
|
||||
}
|
||||
|
||||
EntityType type = EntityType.ZOMBIFIED_PIGLIN; // Default type is piglin
|
||||
|
||||
//Iterating through the drops to remove the added wither skull & ghast tear, if present.
|
||||
Iterator<ItemStack> iter = e.getDrops().iterator();
|
||||
while(iter.hasNext()) {
|
||||
ItemStack is = iter.next();
|
||||
if (is.getType() == Material.WITHER_SKELETON_SKULL) {
|
||||
iter.remove();
|
||||
} else if (is.getType() == Material.GHAST_TEAR) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (e.getEntity().getEquipment().getHelmet().getType() == Material.WITHER_SKELETON_SKULL) {
|
||||
type = EntityType.WITHER_SKELETON;
|
||||
} else if (e.getEntity().getEquipment().getItemInOffHand().getType() == Material.GHAST_TEAR) {
|
||||
type = EntityType.GHAST;
|
||||
}
|
||||
|
||||
if (type != EntityType.ZOMBIFIED_PIGLIN) { // Type is a mock-wither or mock-ghast
|
||||
e.getDrops().clear(); // Clear piglin drops
|
||||
|
||||
if (type == EntityType.GHAST) {
|
||||
int amount = rng.nextInt(2); // Random drop of 0 or 1 Ghast Tear
|
||||
if (amount > 0) {
|
||||
e.getDrops().add(new ItemStack(Material.GHAST_TEAR, amount));
|
||||
}
|
||||
|
||||
amount = rng.nextInt(3); // Random drop of 0, 1, or 2 Gunpowder
|
||||
if (amount > 0) {
|
||||
e.getDrops().add(new ItemStack(Material.GUNPOWDER, amount));
|
||||
}
|
||||
}
|
||||
else { //WITHER
|
||||
int amount = rng.nextInt(3); // Random drop of 0, 1, or 2 Bones
|
||||
if (amount > 0) {
|
||||
e.getDrops().add(new ItemStack(Material.BONE, amount));
|
||||
}
|
||||
|
||||
amount = rng.nextInt(3) -1; // Random drop of -1, 0, or 1 Coal. (1/3 chance for a single coal)
|
||||
if (amount > 0) {
|
||||
e.getDrops().add(new ItemStack(Material.COAL, amount));
|
||||
}
|
||||
|
||||
if (roll(witherHeadDropChance)) { // Standard role for wither skull chance.
|
||||
e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.DataParser;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.utilities.BetterToString;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
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.vehicle.VehicleMoveEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;
|
||||
import vg.civcraft.mc.civmodcore.world.ChunkLoadedFilter;
|
||||
|
||||
public final class ShipOutOfLuck extends BasicHack {
|
||||
|
||||
@AutoLoad(processor = DataParser.MATERIAL)
|
||||
private List<Material> boatBreakers;
|
||||
|
||||
private int ignoredBoatCounter = 0;
|
||||
|
||||
public ShipOutOfLuck(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
// Just in case it's auto loaded to null.
|
||||
if (this.boatBreakers == null) {
|
||||
this.boatBreakers = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.boatBreakers.clear();
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void preventBoatPlacements(final PlayerInteractEvent event) {
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
final Block placedOn = Objects.requireNonNull(event.getClickedBlock());
|
||||
final ItemStack placed = event.getItem();
|
||||
if (!this.boatBreakers.contains(placedOn.getType())
|
||||
|| !ItemUtils.isValidItem(placed)
|
||||
|| !Tag.ITEMS_BOATS.isTagged(placed.getType())) {
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
plugin().debug("Prevented boat placement on [" + placedOn.getType().name() + "] by [" +
|
||||
event.getPlayer().getName() + "] at [" + BetterToString.location(placedOn.getLocation()) + "]");
|
||||
//return;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void preventBoatUsage(final VehicleMoveEvent event) {
|
||||
final Vehicle vehicle = event.getVehicle();
|
||||
if (vehicle.getType() != EntityType.BOAT) {
|
||||
return;
|
||||
}
|
||||
final List<Entity> passengers = vehicle.getPassengers();
|
||||
if (passengers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (++this.ignoredBoatCounter < 40) {
|
||||
return;
|
||||
}
|
||||
this.ignoredBoatCounter = 0;
|
||||
final World world = vehicle.getWorld();
|
||||
final List<Material> illegalBlocks = getCollidingBlocks(vehicle.getBoundingBox())
|
||||
.filter(ChunkLoadedFilter.blockPosition(world))
|
||||
.map(loc -> world.getBlockAt(loc.getX(), loc.getY(), loc.getZ()).getType())
|
||||
.filter(this.boatBreakers::contains)
|
||||
.distinct()
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
if (CollectionUtils.isEmpty(illegalBlocks)) {
|
||||
return;
|
||||
}
|
||||
vehicle.eject();
|
||||
plugin().debug("Ejected [" + passengers.stream().map(CommandSender::getName)
|
||||
.collect(Collectors.joining(", ")) + "] from boat at [" + BetterToString.location(event.getTo())
|
||||
+ "] because they sailed over [" + illegalBlocks.stream().map(Material::name)
|
||||
.collect(Collectors.joining(", ")) + "]");
|
||||
//return;
|
||||
}
|
||||
|
||||
private static Stream<BlockPos> getCollidingBlocks(final BoundingBox bounds) {
|
||||
// This transform the bounds of the boat to be a flat rectangle roughly a carpet's thickness smaller on each
|
||||
// side and placed the same distance below the boat, which should be enough to reliably detect what blocks
|
||||
// are carrying the boat without false alarming with blocks beside the boat.
|
||||
final int minX = (int) Math.floor(bounds.getMinX() + 0.06);
|
||||
final int maxX = (int) Math.floor(bounds.getMaxX() - 0.06);
|
||||
final int valY = (int) Math.floor(bounds.getMinY() - 0.06);
|
||||
final int minZ = (int) Math.floor(bounds.getMinZ() + 0.06);
|
||||
final int maxZ = (int) Math.floor(bounds.getMaxZ() - 0.06);
|
||||
return BlockPos.betweenClosedStream(minX, valY, minZ, maxX, valY, maxZ);
|
||||
}
|
||||
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import com.programmerdan.minecraft.banstick.BanStick;
|
||||
import com.programmerdan.minecraft.banstick.handler.BanStickDatabaseHandler;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public final class StrayStats extends BasicHack {
|
||||
|
||||
public StrayStats(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Bootstrap
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private final StatsCommand statsCommand = new StatsCommand();
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
BanStick.getPlugin();
|
||||
this.plugin.getCommands().registerCommand(this.statsCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.plugin.getCommands().unregisterCommand(this.statsCommand);
|
||||
super.onDisable();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Statistics Commands
|
||||
// ------------------------------------------------------------
|
||||
|
||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
|
||||
|
||||
private class StatsCommand extends BaseCommand {
|
||||
@CommandAlias("compile_player_join_statistics")
|
||||
@CommandPermission("simpleadmin.stats")
|
||||
public void compileStatistics(final CommandSender sender) {
|
||||
sender.sendMessage(ChatColor.GOLD + "Starting to compile player join statistics!");
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin(), () -> {
|
||||
try (final var file = new FileWriter(new File(plugin().getDataFolder(), "playerJoinStats.csv"))) {
|
||||
try (final var connection = BanStickDatabaseHandler.getInstanceData().getConnection();
|
||||
final var statement = connection.prepareStatement(
|
||||
"SELECT name, first_add FROM bs_player ORDER BY first_add ASC");
|
||||
final var query = statement.executeQuery();) {
|
||||
|
||||
while (query.next()) {
|
||||
file.write(query.getString(1) + "," + DATE_FORMAT.format(query.getTimestamp(2)) + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (final IOException | SQLException exception) {
|
||||
plugin().warning("Could not complete compilation!", exception);
|
||||
sender.sendMessage(ChatColor.RED + "Could not complete compilation!");
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(ChatColor.GREEN + "Finished compiling player join statistics!");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.attribute.AttributeInstance;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityBreedEvent;
|
||||
|
||||
public class StriderBreeding extends BasicHack {
|
||||
@AutoLoad
|
||||
private double minSpeed;
|
||||
@AutoLoad
|
||||
private double maxSpeed;
|
||||
@AutoLoad
|
||||
private int minHealth;
|
||||
@AutoLoad
|
||||
private int maxHealth;
|
||||
|
||||
public StriderBreeding(SimpleAdminHacks plugin, BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onStriderBreed(EntityBreedEvent event) {
|
||||
if (event.getEntity().getType() != EntityType.STRIDER) {
|
||||
return;
|
||||
}
|
||||
double dadSpeed = event.getFather().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue();
|
||||
double mumSpeed = event.getMother().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue();
|
||||
double randomSpeed = Math.random() * (this.maxSpeed - this.minSpeed) + this.minSpeed;
|
||||
//the 0.44.... number, I was given this number by Okx#5481, apparently it is the horse speed generation number
|
||||
//Also worth noting he told me it is not exactly a bell curve even if I did name it bellCurve
|
||||
double bellCurve = (0.44999998807907104 + randomSpeed * 0.3 + randomSpeed * 0.3 + randomSpeed * 0.3) * 0.25;
|
||||
double newStriderSpeed = (dadSpeed + mumSpeed + bellCurve) / 3;
|
||||
if (newStriderSpeed < minSpeed) {
|
||||
newStriderSpeed = minSpeed;
|
||||
} else if (newStriderSpeed > maxSpeed) {
|
||||
newStriderSpeed = maxSpeed;
|
||||
}
|
||||
event.getEntity().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(newStriderSpeed);
|
||||
|
||||
double dadHealth = event.getFather().getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue();
|
||||
double mumHealth = event.getFather().getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue();
|
||||
double randomHealth = Math.random() * (this.maxHealth - this.minHealth) + this.minHealth;
|
||||
double newStriderHealth = Math.round(((float) dadHealth + (float) mumHealth + (float) randomHealth) / 3);
|
||||
if (newStriderHealth < minHealth) {
|
||||
newStriderHealth = minHealth;
|
||||
} else if (newStriderHealth > maxHealth) {
|
||||
newStriderHealth = maxHealth;
|
||||
}
|
||||
event.getEntity().getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(newStriderHealth);
|
||||
event.getEntity().setHealth(newStriderHealth);
|
||||
plugin.getLogger().log(Level.INFO, "Strider breed to have speed: " + newStriderSpeed
|
||||
+ " and health: " + newStriderHealth);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onStriderSpawn(CreatureSpawnEvent event) {
|
||||
if (event.getEntity().getType() != EntityType.STRIDER) {
|
||||
return;
|
||||
}
|
||||
if (event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.BREEDING) {
|
||||
return;
|
||||
}
|
||||
rollSpeedStat(event.getEntity(), this.minSpeed, this.maxSpeed);
|
||||
rollHealthStat(event.getEntity(), this.minHealth, this.maxHealth);
|
||||
}
|
||||
|
||||
public void rollSpeedStat(LivingEntity strider, double minSpeed, double maxSpeed) {
|
||||
AttributeInstance moveSpeed = strider.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
|
||||
if (moveSpeed == null) {
|
||||
return;
|
||||
}
|
||||
double random = Math.random() * (maxSpeed - minSpeed) + minSpeed;
|
||||
double bellCurve = (0.44999998807907104 + random * 0.3 + random * 0.3 + random * 0.3) * 0.25;
|
||||
if (bellCurve < minSpeed) {
|
||||
bellCurve = minSpeed;
|
||||
} else if (bellCurve > maxSpeed) {
|
||||
bellCurve = maxSpeed;
|
||||
}
|
||||
moveSpeed.setBaseValue(bellCurve);
|
||||
plugin.getLogger().log(Level.INFO, "Setting Strider Speed to: " + bellCurve);
|
||||
}
|
||||
|
||||
public void rollHealthStat(LivingEntity strider, int minHealth, int maxHealth) {
|
||||
AttributeInstance moveSpeed = strider.getAttribute(Attribute.GENERIC_MAX_HEALTH);
|
||||
if (moveSpeed == null) {
|
||||
return;
|
||||
}
|
||||
int newValue = Math.round((float) Math.random() * (maxHealth - minHealth) + minHealth);
|
||||
if (newValue < minHealth) {
|
||||
newValue = minHealth;
|
||||
} else if (newValue > maxHealth) {
|
||||
newValue = maxHealth;
|
||||
}
|
||||
moveSpeed.setBaseValue(newValue);
|
||||
//We set the health to the new value since when we update the health, they dont auto heal
|
||||
strider.setHealth(newValue);
|
||||
plugin.getLogger().log(Level.INFO, "Setting Strider Health to: " + newValue);
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks.hacks.basic;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
public final class TestConfigHack extends BasicHack {
|
||||
|
||||
@AutoLoad
|
||||
private boolean boolValue;
|
||||
|
||||
@AutoLoad
|
||||
private byte byteValue;
|
||||
|
||||
@AutoLoad
|
||||
private short shortValue;
|
||||
|
||||
@AutoLoad
|
||||
private int intValue;
|
||||
|
||||
@AutoLoad
|
||||
private long longValue;
|
||||
|
||||
@AutoLoad
|
||||
private long maybeLongValue;
|
||||
|
||||
@AutoLoad
|
||||
private float floatValue;
|
||||
|
||||
@AutoLoad
|
||||
private double doubleValue;
|
||||
|
||||
@AutoLoad
|
||||
private char charValue;
|
||||
|
||||
public TestConfigHack(final SimpleAdminHacks plugin, final BasicHackConfig config) {
|
||||
super(plugin, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
// boolean
|
||||
if (this.boolValue) {
|
||||
this.plugin.info(ChatColor.GREEN + "Boolean value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Boolean value failed.");
|
||||
}
|
||||
// byte
|
||||
if (this.byteValue == (byte) 8) {
|
||||
this.plugin.info(ChatColor.GREEN + "Byte value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Byte value failed: " + this.byteValue);
|
||||
}
|
||||
// short
|
||||
if (this.shortValue == (short) 14646) {
|
||||
this.plugin.info(ChatColor.GREEN + "Short value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Short value failed: " + this.shortValue);
|
||||
}
|
||||
// int
|
||||
if (this.intValue == 33822776) {
|
||||
this.plugin.info(ChatColor.GREEN + "Int value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Int value failed: " + this.intValue);
|
||||
}
|
||||
// long
|
||||
if (this.longValue == 2486941267899177L) {
|
||||
this.plugin.info(ChatColor.GREEN + "Long value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Long value failed: " + this.longValue);
|
||||
}
|
||||
// long - second, ambiguous test
|
||||
if (this.maybeLongValue == 6543L) {
|
||||
this.plugin.info(ChatColor.GREEN + "Long (ambiguous) value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Long (ambiguous) value failed: " + this.maybeLongValue);
|
||||
}
|
||||
// float
|
||||
if (this.floatValue == 3847.1234f) {
|
||||
this.plugin.info(ChatColor.GREEN + "Float value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Float value failed: " + this.floatValue);
|
||||
}
|
||||
// double
|
||||
if (this.doubleValue == 345978623.178569873d) {
|
||||
this.plugin.info(ChatColor.GREEN + "Double value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Double value failed: " + this.doubleValue);
|
||||
}
|
||||
// char
|
||||
if (this.charValue == 'c') {
|
||||
this.plugin.info(ChatColor.GREEN + "Char value passes!");
|
||||
}
|
||||
else {
|
||||
this.plugin.info(ChatColor.RED + "Char value failed: " + this.charValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
# Effectively Modern Humbug. For 1.10 ground up.
|
||||
|
||||
configuration_file_version: 1
|
||||
|
||||
debug: true
|
||||
broadcast_permission: simpleadmin.broadcast
|
||||
|
||||
hacks:
|
||||
############################################################
|
||||
## Basic Hacks
|
||||
############################################################
|
||||
AntiFastBreak:
|
||||
enabled: true
|
||||
breakDenyDuration: 3000
|
||||
laggLenciency: 1.2
|
||||
#Prevents pearls from landing that have been in flight for more than the configured amount of time
|
||||
AntiStatisChamber:
|
||||
enabled: true
|
||||
pearlLifetime: 5m
|
||||
#Bounds armour to specific players disallowing others to wear the same armour piece after first equip
|
||||
ArmourBound:
|
||||
enabled: true
|
||||
whitelist:
|
||||
- DIAMOND_HELMET
|
||||
- DIAMOND_CHESTPLATE
|
||||
- DIAMOND_LEGGINGS
|
||||
- DIAMOND_BOOTS
|
||||
- NETHERITE_HELMET
|
||||
- NETHERITE_CHESTPLATE
|
||||
- NETHERITE_LEGGINGS
|
||||
- NETHERITE_BOOTS
|
||||
ArthropodEggHack:
|
||||
enabled: true
|
||||
eggChance: 0.03
|
||||
lootingChance: 0.02
|
||||
removeDrops: true
|
||||
allowedTypes:
|
||||
- SHEEP
|
||||
- PIG
|
||||
- COW
|
||||
- BAT
|
||||
- CHICKEN
|
||||
- WOLF
|
||||
- SQUID
|
||||
- MUSHROOM_COW
|
||||
- RABBIT
|
||||
- HORSE
|
||||
- VILLAGER
|
||||
- LLAMA
|
||||
- OCELOT
|
||||
- FOX
|
||||
- COD
|
||||
- TROPICAL_FISH
|
||||
- SALMON
|
||||
- TURTLE
|
||||
- DOLPHIN
|
||||
AttrHider:
|
||||
enabled: true
|
||||
# Hide item data like enchantments, firework effects, book data, potion, etc..
|
||||
hideItemMeta: true
|
||||
# Hide potion effects on entities, except for particles
|
||||
hideEffects: true
|
||||
# Hide the health of entities
|
||||
hideHealth: true
|
||||
AutoRespawn:
|
||||
enabled: true
|
||||
# Delay in MS
|
||||
# Default: 300000 (five minutes)
|
||||
respawnDelay: 300000
|
||||
# The respawn delay (in MS) if someone logs in dead
|
||||
# Default 0 (instant)
|
||||
loginRespawnDelay: 0
|
||||
# Jokey joke messages sent to the player if auto-respawned
|
||||
# Deactivate by removing all the quotes below
|
||||
respawnQuotes:
|
||||
- <gold>Wait... how did I get here?
|
||||
- <gold>Must've been a rough night o.o
|
||||
- <gold>Why does my entire body ache?
|
||||
- <gold>That <it>really<gold> hurt!
|
||||
BedLocator:
|
||||
enabled: true
|
||||
BeeKeeping:
|
||||
enabled: true
|
||||
# Value between 0 and 1 that determines the percentage chance that a bee will replace
|
||||
# the natural spawning of a passive creature should certain conditions be met.
|
||||
# Default: 0.2 (20%)
|
||||
spawnChance: 0.2
|
||||
# Value between 0 and 1 that determines the percentage chance that a bee will lose
|
||||
# its stinger and thus die when successfully attacking an entity.
|
||||
# Default: 1.0 (100%)
|
||||
severStingerChance: 1.0
|
||||
BuffSpanker:
|
||||
enabled: true
|
||||
# The list of PotionEffectType's that you do not wish players to receive.
|
||||
naughty:
|
||||
- DOLPHINS_GRACE
|
||||
- BAD_OMEN
|
||||
- SLOW_DIGGING
|
||||
- SLOW_FALLING
|
||||
DebugWand:
|
||||
enabled: true
|
||||
DogFacts:
|
||||
enabled: false
|
||||
intervalTime: 30m
|
||||
#Since we use the tellraw command to dispatch dogfacts now, all our announcements **MUST** be in JSON format
|
||||
#YAML also doesn't like JSON's usage of "" so we have to add escape characters (\) to counteract that.
|
||||
#Here's the site I used to make these ones: https://minecraft.tools/en/json_text.php
|
||||
announcements:
|
||||
- "[\"\",{\"text\":\"Buy \"},{\"text\":\"Dogecoin\",\"color\":\"dark_red\",\"clickEvent\":{\"action\":\"open_url\",\"value\":\"https://www.coindesk.com/price/dogecoin\"}},{\"text\":\"!\"}]"
|
||||
- "[\"\",{\"text\":\"Very \"},{\"text\":\"Wow!\",\"italic\":true,\"hoverEvent\":{\"action\":\"show_text\",\"contents\":\"Wow!\"}}]"
|
||||
EventDebugHack:
|
||||
enabled: true
|
||||
EventHandlerList:
|
||||
enabled: true
|
||||
GoldBlockElevators:
|
||||
enabled: true
|
||||
HumbugBatchOne:
|
||||
enabled: true
|
||||
allowSheepDying: true
|
||||
allowUsingAnvils: true
|
||||
allowUsingEnchantingTables: true
|
||||
infiniteCauldrons: true
|
||||
disableEnderDragon: true
|
||||
disableIronFarms: true
|
||||
disableEnderCrystalDamage: true
|
||||
disableMiningFatigue: true
|
||||
canEquipBanners: true
|
||||
disableLavaCobbleMountains: true
|
||||
disableWanderingTrader: true
|
||||
preventPearlGlitching: true
|
||||
preventUsingEyeOfEnder: true
|
||||
disablePiglins: true
|
||||
disableGapples: true
|
||||
ItemMetaConverterHack:
|
||||
enabled: true
|
||||
OldEnchanting:
|
||||
enabled: true
|
||||
# Hides what enchantment will be granted within the Enchanting Table
|
||||
hideEnchants: true
|
||||
# Automatically fills the consumable slot with the Enchanting Table with Lapis Lazuli that cannot be taken
|
||||
fillLapis: true
|
||||
# Randomises the enchantment offers each time the item is placed in an Enchanting Table
|
||||
randomiseEnchants: true
|
||||
# Force enchantments to cost what they appear in the Enchanting Table
|
||||
fixEnchantCosts: true
|
||||
# Experience modifier, all experience drops will be multiplied by this (does not apply to player exp)
|
||||
# NOTE: Modifier must be 0 or greater
|
||||
experienceModifier: 0.2
|
||||
# Loot modifier, multiply the amount of exp dropped from each level of Looting (does not apply to player exp)
|
||||
# NOTE: Modifier must be 0 or greater
|
||||
lootModifier: 1.5
|
||||
# Enables xp bottles to be crafted from emeralds and vice versa
|
||||
emeraldCrafting: true
|
||||
# Enables gaining xp from emeralds directly if emeraldCrafting is enabled
|
||||
emeraldLeveling: true
|
||||
# Disables exp from mobs, fishing, mining, breeding, furnace extracting, etc
|
||||
disableGrindExp: true
|
||||
# Prevents exp orbs from granting xp
|
||||
preventOrbExp: true
|
||||
# Ensures that the player who threw the xp bottle is the one to get the xp (experienceModifier does not apply)
|
||||
directBottleExp: true
|
||||
# Defines the maximum repair cost of an item
|
||||
# NOTE: Value must be 2 or greater, or -1 to disable
|
||||
maxRepairCost: 33
|
||||
# Defines the set amount of xp that xp bottles will produce
|
||||
# NOTE: Value must be a 0 or greater, or -1 for vanilla random
|
||||
expPerBottle: 10
|
||||
# Allows player's to store their levels in bottles if expPerBottle has a value higher than 0
|
||||
allowExpRecovery: true
|
||||
# Disallows players from creating enchanted books
|
||||
disableEnchantedBookCreation: true
|
||||
# Disallows players from using enchanted books
|
||||
disableEnchantedBookUsage: true
|
||||
# Modifies the exp drops for specific mob types, which will be used in lieu of experienceModifier
|
||||
# NOTE: Players have an implicit modifier of 1.0
|
||||
# NOTE: Modifiers must be 0 or greater
|
||||
entityExpDropModifiers:
|
||||
ENDER_DRAGON: 0.1
|
||||
PhantomMenace:
|
||||
enabled: true
|
||||
# Players have a statistic called TIME_SINCE_REST. If a player's value is above 72k (3 days minecraft time) then
|
||||
# they will start spawning phantoms. Setting the cap to below 72k will effectively disable phantoms. Setting the
|
||||
# cap to -1 will disable the cap. Default: 80k (10% chance per two minutes during the night and thunder storms.)
|
||||
# Read more here: https://minecraft.gamepedia.com/Phantom#Java_Edition
|
||||
timeSinceRestCap: 80000
|
||||
# Determines whether phantoms are allowed to spawn during the night.
|
||||
nightSpawn: true
|
||||
# Determines whether phantoms are allowed to spawn during thunder storms.
|
||||
stormSpawn: true
|
||||
# Determines what the maximum light level is that phantoms can spawn to.
|
||||
maximumLightSpawn: 7
|
||||
PlayerRevive:
|
||||
enabled: true
|
||||
PlayerStatistics:
|
||||
enabled: true
|
||||
PortalSpawnModifier:
|
||||
enabled: true
|
||||
pigManChance: 0.5
|
||||
ghastChance: 0.07
|
||||
witherSkeletonChance: 0.05
|
||||
witherHeadDropChance: 0.04
|
||||
ShipOutOfLuck:
|
||||
enabled: true
|
||||
# The list of Material's that boats cannot be placed on and will eject passengers
|
||||
boatBreakers:
|
||||
- ICE
|
||||
- PACKED_ICE
|
||||
- FROSTED_ICE
|
||||
- BLUE_ICE
|
||||
StrayStats:
|
||||
enabled: true
|
||||
TestConfigHack:
|
||||
enabled: true
|
||||
# Please do not change any of the values below, otherwise it will undermine the test.
|
||||
boolValue: true
|
||||
byteValue: 8
|
||||
shortValue: 14646
|
||||
intValue: 33822776
|
||||
longValue: 2486941267899177
|
||||
maybeLongValue: 6543
|
||||
floatValue: 3847.1234
|
||||
doubleValue: 345978623.178569873
|
||||
charValue: 'c'
|
||||
############################################################
|
||||
## Simple Hacks
|
||||
############################################################
|
||||
BadBoyWatch:
|
||||
enabled: true
|
||||
trackingDepth: 16
|
||||
clearOnMatch: true
|
||||
watchedMaterials:
|
||||
- CHEST
|
||||
- FURNACE
|
||||
- DROPPER
|
||||
- DISPENSER
|
||||
- JUKEBOX
|
||||
- NOTE_BLOCK
|
||||
- BEACON
|
||||
- ENDER_CHEST
|
||||
- SPONGE
|
||||
- HOPPER
|
||||
- PISTON_BASE
|
||||
- PISTON_STICKY_BASE
|
||||
- OBSERVER
|
||||
CTAnnounce:
|
||||
enabled: false
|
||||
delay: 10000
|
||||
message: '%Victim% was combat tagged by %Attacker%'
|
||||
broadcast: [OP, CONSOLE]
|
||||
DisableAI:
|
||||
enabled: true
|
||||
# Specify below the living entities and their spawning circumstances you want to disable the AI for.
|
||||
# NOTE: See https://papermc.io/javadocs/paper/1.16/org/bukkit/entity/EntityType.html
|
||||
# NOTE: See https://papermc.io/javadocs/paper/1.16/org/bukkit/event/entity/CreatureSpawnEvent.SpawnReason.html
|
||||
# Note: You can also just state "ALL" for all spawn circumstances
|
||||
VILLAGER: ALL
|
||||
ENDERMITE: [DISPENSE_EGG, EGG, SPAWNER_EGG]
|
||||
ElytraFeatures:
|
||||
enabled: true
|
||||
# Whether Elytra flight should be outright disabled
|
||||
disableFlight: false
|
||||
# Whether Elytra flight should be disabled in combat
|
||||
disableFlightInCombat: false
|
||||
# Whether firework boosting should be outright disabled
|
||||
disableFireworkBoosting: false
|
||||
# Whether firework boosting should be disabled in combat
|
||||
disableFireworkBoostingInCombat: false
|
||||
# Whether to restrict firework boosting to explosive fireworks
|
||||
disableSafeFireworkBoosting: false
|
||||
# This regulates player damage when Elytra flying above world height.
|
||||
heightDamage:
|
||||
# The amount of damage (in half-hearts) the flier should take.
|
||||
# NOTE: Setting to 0 will disable the damage.
|
||||
damage: 1
|
||||
# The damage is multiplied by the number of blocks above world height multiplied by this number.
|
||||
scales: 1.0
|
||||
# The amount of blocks above height limit where damage is not applied.
|
||||
buffer: 5
|
||||
# The interval (in milliseconds) between damage ticks.
|
||||
interval: 1000
|
||||
Experimental:
|
||||
enabled: true
|
||||
combatspy: false
|
||||
teleportspy: false
|
||||
postteleport:
|
||||
spy: false
|
||||
count: 10
|
||||
GameFeatures:
|
||||
enabled: true
|
||||
disablePotatoXP: false
|
||||
# Villager trading is not like above and true = able to trade and false = not able
|
||||
villagerTrading: false
|
||||
# Wither spawn is also true = enabled and false = disabled
|
||||
witherSpawning: false
|
||||
# Prevent or allow pillager patrols from spawning
|
||||
# Patrols spawning is also true = enabled and false = disabled
|
||||
patrolSpawning: false
|
||||
# Phantom spawn is also true = enabled and false = disabled
|
||||
phantomSpawning: false
|
||||
# Enderchests is also true = enabled and false = disabled
|
||||
enderChestPlacement: true
|
||||
enderChestUse: false
|
||||
chorusFruitTeleportation: false
|
||||
# WeepingAngel bans people when they die, the numbers are in milliseconds.
|
||||
weepingAngel:
|
||||
enabled: false
|
||||
environment: 60000 # 1 Minute
|
||||
playerKill: 300000 # 5 Minutes
|
||||
# prevent use of buckets or dispensing water in hell biomes
|
||||
blockWaterInHell: true
|
||||
minecartTeleport: true
|
||||
obsidianGenerators: true
|
||||
personalDeathMessages: true
|
||||
disableNetheriteCrafting: true
|
||||
goldBlockTeleport: false
|
||||
GameFixes:
|
||||
enabled: true
|
||||
# Does not fully work atm
|
||||
blockElytraBreakBug: false
|
||||
damageOnElytraBreakBug: 1.0
|
||||
canStorageTeleport: false
|
||||
stopHopperDupe: true
|
||||
stopRailDupe: true
|
||||
stopEndPortalDeletion: true
|
||||
stopBedBombingInHellBiomes: true
|
||||
stopAnchorBombing: true
|
||||
preventTreeWraparound: true
|
||||
maintainFlatBedrock: false
|
||||
fixPearlGlitch: true
|
||||
preventLongSigns: true
|
||||
signLengthLimit: 100
|
||||
preventLongSignsAbsolute: true
|
||||
cancelLongSignEvent: false
|
||||
hardLimitBookPageCount: true
|
||||
GameTuning:
|
||||
enabled: true
|
||||
chunkLimits:
|
||||
enabled: true
|
||||
exceededMessage: '&9Limit reached for this chunk, you cannot place more of this type of block.'
|
||||
tileEntities:
|
||||
HOPPER: 4
|
||||
PISTON_BASE: 4
|
||||
PISTON_STICKY_BASE: 4
|
||||
DISPENSER: 4
|
||||
DROPPER: 4
|
||||
REDSTONE_COMPARATOR: 4
|
||||
OBSERVER: 2
|
||||
exempt:
|
||||
- Steve
|
||||
- Alex
|
||||
daytimeBed:
|
||||
enabled: true
|
||||
spawnSetMessage: '&7Your spawn has been set.'
|
||||
# Makes nether ratio 1 to 1
|
||||
oneToOneNether: false
|
||||
# Return nether portal, true = enabled false = disabled
|
||||
returnNetherPortal: true
|
||||
allowNetherTravel: false
|
||||
# Disables minecart inventories (trying to fix dupe issues)
|
||||
# enabled = able to right click disabled = not able to right click
|
||||
chestedMinecartInventories: true
|
||||
hopperMinecartInventories: true
|
||||
enderChestInventories: false
|
||||
stopTrapHorses: true
|
||||
killTrapHorses: true
|
||||
changeSpawnerType: false
|
||||
allowVillagerTrading: false
|
||||
enderGrief: false
|
||||
witherGrief: false
|
||||
dragonGrief: true
|
||||
allowEnchantedApples: false
|
||||
preventFallingThroughBedrock: true
|
||||
# Disable the Bad Omen effect that player receive when killing pillager patrols
|
||||
badOmen: false
|
||||
#a list of materials players shouldn't be allowed to place at all
|
||||
noplace:
|
||||
- DRAGON_EGG
|
||||
rainReduction:
|
||||
enabled: false
|
||||
rainOccurrenceChance: .5
|
||||
HorseStats:
|
||||
enabled: false
|
||||
wand: COMPASS
|
||||
Insight:
|
||||
enabled: false
|
||||
into:
|
||||
- org.bukkit.event.player
|
||||
- org.bukkit.event.entity
|
||||
- org.bukkit.event.block
|
||||
- org.bukkit.event.inventory
|
||||
- org.bukkit.event.enchantment
|
||||
- org.bukkit.event.hanging
|
||||
- org.bukkit.event.painting
|
||||
- org.bukkit.event.vehicle
|
||||
- org.bukkit.event.weather
|
||||
- org.bukkit.event.world
|
||||
Introbook:
|
||||
enabled: true
|
||||
follow: true
|
||||
contents:
|
||||
title: Welcome, ${player}
|
||||
author: Bonkill
|
||||
pages:
|
||||
- " &oWelcome to Devoted, ${player}!"
|
||||
- " &oWhat is Devoted?\n\"A new type of Minecraft server built towards providing a competitive, high stakes, immersive experience controlled by the players.\"&r\n-ShadedJon, server owner"
|
||||
- " &oWhat is Devoted?&r\n&lNOT just survival&r\nAdmins are hands-off and only handle glitches and hackers\n&lNOT just chaos&r\nPlugins allow players and towns to enforce their own rules\n&lNOT just roleplay&r\nNobody pretends -- conflict is genuine and heated"
|
||||
- " &oBasic Mechanics&r\n-The world is custom generated\n-Many custom biomes\n-Limited chat range\n-Respawn in random area unless you sleep\n-Mobs spawn sparsely\n-Vanilla Nether\n-Ore veins and custom ore spawning."
|
||||
- " &oDevoted Mods&r\n &lCitadel&r:\n Reinforces things so it takes numerous breaks to destroy them. Locks some things too.\n&lMore Info:&r &oVisual Guide:&r imgur.com/BnlL2 &oWiki Page:&r tinyurl.com/citadelmod\n&oType \"/help citadel\" in chat to get commands"
|
||||
- " &lPrison Pearl&r:\n Ender Pearls trap players in the end. Others can steal back your pearl and free you -- you always know where it is so they cannot hide it\n&lMore Info:&r &oVisual Guide:&r imgur.com/XbhkK &oWiki Page:&r tinyurl.com/prisperl"
|
||||
- " &lJuke Alert&r:\n Creates 'Juke' blocks that record player activity in radius. If you steal, grief, or trespass -- people will know about it & put a bounty for you to be pearled.\n&lMore Info:&r &oWiki Page:&r tinyurl.com/snitchblock"
|
||||
- " &lMythicMobs&r:\n Some custom mobs to increase the risk and thrill on specific islands and areas throughout Devoted.\n&lMore Info:&r &oBukkit Page:&r dev.bukkit.org/bukkit-plugins/mythicmobs"
|
||||
- " &lItem Exchange&r:\n It's a minecraft shop mod that enables different chests (and other inventory blocks) to perform an exchange of items with a player.\n&lMore Info:&r &oWiki Page:&r tinyurl.com/itemxchng"
|
||||
- " &lHumbug&r:\n Disables some features of minecraft -- see wiki for short list. Please read it to ensure you don't waste resources on a useless block.\n&lMore Info:&r &oWiki Page:&r tinyurl.com/humbugwiki"
|
||||
- " &lRealistic Biomes&r:\n Biomes are large, crops grow different in different biomes. Hit ground with seed to see growth rate. Farms need sunlight. Crops grow with nobody around.\n&lMore Info:&r &oWiki Page:&r tinyurl.com/realbiome"
|
||||
- " &lArthropod Egg&r:\n Allows you to capture passive mobs into spawn eggs using Bane of Arthropod enchantment.\n&lMore Info:&r &oGithub Page:&r tinyurl.com/arthrop"
|
||||
- " &lBrewery&r:\n Custom brewing of booze and more.\n&lMore Info:&r &oBukkit Page:&r tinyurl.com/bukkitbrewp"
|
||||
- " &oFurther Info&r\nVisit our subreddit at: &oreddit.com/r/Devoted&r"
|
||||
- "We extend our appreciation to the devs, admins, and players at: &oreddit.com/r/Civcraft"
|
||||
InvControl:
|
||||
enabled: true
|
||||
NewfriendAssist:
|
||||
enabled: true
|
||||
announce: '&f%Player% is brand new!'
|
||||
giveIntroKitToRandomSpawners: true
|
||||
broadcast: [PERM, CONSOLE]
|
||||
helptips: on
|
||||
helptips_end: 20m
|
||||
introkit:
|
||||
enabled: true
|
||||
contents:
|
||||
- ==: org.bukkit.inventory.ItemStack
|
||||
v: 1
|
||||
type: COOKIE
|
||||
amount: 32
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: 'Manna'
|
||||
lore:
|
||||
- "Gift from the Admins as you"
|
||||
- "begin your journey on Devotion."
|
||||
- ==: org.bukkit.inventory.ItemStack
|
||||
v: 1
|
||||
type: RED_BED
|
||||
amount: 1
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
lore:
|
||||
- "This world is unforgiving."
|
||||
- "Be sure to get a good night's"
|
||||
- "rest soon."
|
||||
ReinforcedChestBreak:
|
||||
enabled: true
|
||||
# in seconds
|
||||
delay: 180
|
||||
message: "&4%player% is raiding a chest at %x% %y% %z%."
|
||||
SanityHack:
|
||||
enabled: true
|
||||
trackPlace: true
|
||||
trackBreak: true
|
||||
belowYLevel: 7
|
||||
#Currently changes a striders speed to be between 0.175 (Default) and 0.3375 (Horse max speed)
|
||||
#aswell as default health to between 20 (Default) and 50 (2.5 heart bars)
|
||||
#Only works on newly spawned striders, not pre-existing mobs
|
||||
StriderBreeding:
|
||||
enabled: true
|
||||
#Default strider speed is 0.175
|
||||
minSpeed: 0.175
|
||||
#Max horse speed is 0.3375
|
||||
maxSpeed: 0.3375
|
||||
#10 Hearts
|
||||
minHealth: 20
|
||||
#25 Hearts
|
||||
maxHealth: 50
|
||||
TimingsHack:
|
||||
enabled: true
|
||||
ToggleLamp:
|
||||
enabled: false
|
||||
cooldownTime: 100
|
||||
@@ -0,0 +1,160 @@
|
||||
name: ${name}
|
||||
main: com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks
|
||||
author: ProgrammerDan
|
||||
authors: [ProgrammerDan, Maxopoly]
|
||||
version: ${version}
|
||||
depend: [CivModCore]
|
||||
softdepend: [CombatTagPlus, NameLayer, Citadel, ProtocolLib]
|
||||
api-version: 1.18
|
||||
commands:
|
||||
hacks:
|
||||
description: Shows the various hacks and fixes supported by this plugin and controls them
|
||||
usage: |
|
||||
/<command>
|
||||
/<command> <hackname>
|
||||
/<command> <hackname> enable|disable
|
||||
/<command> <hackname> get|set <config> [value]
|
||||
permission: simpleadmin.hacks
|
||||
invsee:
|
||||
description: See any player inventory, online or not.
|
||||
usage: /<command> [playername|UUID]
|
||||
permission: simpleadmin.invsee
|
||||
invmod:
|
||||
description: Modify any player inventory, online or not.
|
||||
usage: /<command> [playername|UUID]
|
||||
permission: simpleadmin.invmod
|
||||
chunklimits:
|
||||
description: Display block chunk limit in chat
|
||||
usage: /<command>
|
||||
serialize:
|
||||
description: Print to console the object held as serialized yaml
|
||||
usage: /<command>
|
||||
permission: simpleadmin.hacks
|
||||
introkit:
|
||||
description: Give a player the currently configured introkit
|
||||
usage: /<command> [playername|UUID]
|
||||
permission: simpleadmin.kit
|
||||
introbook:
|
||||
description: Give a player the currently configured intro book
|
||||
usage: /<command> [playername|UUID]
|
||||
permission: simpleadmin.book
|
||||
hackbot:
|
||||
description: Allows the creation of NPCs
|
||||
usage: |
|
||||
/<command> spawn [npc name]
|
||||
/<command> despawn [npc name]
|
||||
/<command> save [npc name]
|
||||
/<command> generate [npc name] [name of skin] [spawn <world,x,y,z>] [options and flags]
|
||||
/<command> help generate shows detailed help on the generate subcommand
|
||||
/<command> destroy [npc name]
|
||||
/<command> all save
|
||||
/<command> all despawn
|
||||
/<command> all spawn
|
||||
/<command> [status|list]
|
||||
permission: simpleadmin.bots
|
||||
showtimings:
|
||||
description: Get an in-game map that shows tick length and distribution over time (2 mins, updated continuously)
|
||||
usage: /<command>
|
||||
permission: simpleadmin.timings
|
||||
bindtimings:
|
||||
description: Get an in-game map that shows relative tick usage by a targetted class
|
||||
usage: /<command> classname
|
||||
permission: simpleadmin.timings
|
||||
thresholdtimings:
|
||||
description: Get periodic reports on misbehaving classes using a lot of tick time, based on a threshold (as a factor * avg tick)
|
||||
usage: /<command> threshold
|
||||
permission: simpleadmin.timings
|
||||
listtimings:
|
||||
description: Show all Classes that can be used with bindtimings; this is a progressive report function that continues until nothing new is seen
|
||||
usage: /<command>
|
||||
permission: simpleadmin.timings
|
||||
stoptimings:
|
||||
description: Stop any advanced timing tracking. Does not stop /showtimings reults.
|
||||
usage: /<command>
|
||||
permission: simpleadmin.timings
|
||||
insight:
|
||||
description: Event insights. Passively tracks stuff, or actively represents events for players.
|
||||
usage: |
|
||||
/<command> on
|
||||
/<command> active - Activates active monitoring of events. For continuous events, pings you with a summary update every 5 seconds. For initiated events, pings you immediately.
|
||||
/<command> off
|
||||
/<command> inactive - Deactivates active monitoring.
|
||||
/<command> list - Shows all monitored events and some stats about each
|
||||
/<command> list <event> - Shows all monitored events that match the passed param <event>
|
||||
/<command> periodic <time> - Shows a color differentiated summary of monitored events and counts that have changed, with <time> as ticks inbetween display
|
||||
/<command> periodic <event> <time> - Shows a color differentiated summary of monitored evenst that match the passed param <event>, with <time> as ticks inbetween display
|
||||
/<command> - Just shows this description
|
||||
debugevent:
|
||||
description: Allows debugging of an event and its handlers
|
||||
usage: /<command> full.path.to.event
|
||||
permission: simpleadmin.eventdebug
|
||||
stats: {} # Defined in (basic) PlayerStats
|
||||
permissions:
|
||||
simpleadmin.*:
|
||||
description: Gives access to all SimpleAdminHacks commands
|
||||
default: op
|
||||
children:
|
||||
simpleadmin.hacks: true
|
||||
simpleadmin.invsee: true
|
||||
simpleadmin.chestsee: true
|
||||
simpleadmin.invmod: true
|
||||
simpleadmin.chestmod: true
|
||||
simpleadmin.kit: true
|
||||
simpleadmin.book: true
|
||||
simpleadmin.broadcast: true
|
||||
simpleadmin.bots: true
|
||||
simpleadmin.timings: true
|
||||
simpleadmin.eventdebug: true
|
||||
simpleadmin.stats: true
|
||||
simpleadmin.revive: true
|
||||
simpleadmin.debugwand: true
|
||||
simpleadmin.bedlocator: true
|
||||
simpleadmin.elytrabypass: true
|
||||
simpleadmin.hacks:
|
||||
description: Allows control of the hacks and settings which simpleadminhacks supports
|
||||
default: op
|
||||
simpleadmin.invsee:
|
||||
description: Allows viewing player inventory
|
||||
default: op
|
||||
simpleadmin.chestsee:
|
||||
description: Allows viewing any chests
|
||||
default: op
|
||||
simpleadmin.invmod:
|
||||
description: Allows modifying player inventory
|
||||
default: op
|
||||
simpleadmin.chestmod:
|
||||
description: Allows modifying any chests
|
||||
default: op
|
||||
simpleadmin.kit:
|
||||
description: Gives ability to gift starting kit
|
||||
default: op
|
||||
simpleadmin.book:
|
||||
description: Gives ability to gift starting book
|
||||
default: op
|
||||
simpleadmin.broadcast:
|
||||
description: Gives the holder the ability to receive broadcasts
|
||||
default: op
|
||||
simpleadmin.bots:
|
||||
description: Gives the ability to create NPCs (bots)
|
||||
default: op
|
||||
simpleadmin.timings:
|
||||
description: Gives the ability to view and manage /...timings commands
|
||||
default: op
|
||||
simpleadmin.eventdebug:
|
||||
description: Gives the ability to view and manage /...timings commands
|
||||
default: op
|
||||
simpleadmin.stats:
|
||||
description: Gives the ability to view and manage player statistics
|
||||
default: op
|
||||
simpleadmin.revive:
|
||||
description: Gives the ability to revive players
|
||||
default: op
|
||||
simpleadmin.debugwand:
|
||||
description: Gives the ability to create and use debug wands
|
||||
default: op
|
||||
simpleadmin.bedlocator:
|
||||
description: Gives the ability to locate your own bed
|
||||
default: true
|
||||
simpleadmin.elytrabypass:
|
||||
description: Gives the ability to bypass elytra restrictions
|
||||
default: op
|
||||
@@ -1 +1 @@
|
||||
# Test config will go here.
|
||||
# Test config will go here.
|
||||
@@ -1,145 +0,0 @@
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.programmerdan.minecraft</groupId>
|
||||
<artifactId>SimpleAdminHacks</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.6</version>
|
||||
<name>SimpleAdminHacks</name>
|
||||
<url>https://github.com/DevotedMC/SimpleAdminHacks</url>
|
||||
|
||||
<build>
|
||||
<finalName>${project.name}-${project.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<compilerArgument></compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.19.1</version>
|
||||
<configuration>
|
||||
<testFailureIgnore>true</testFailureIgnore>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<instrumentation>
|
||||
<excludes>
|
||||
<exclude>com/programmerdan/minecraft/simpleadminhacks/**/*Test.class</exclude>
|
||||
</excludes>
|
||||
</instrumentation>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>clean</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${basedir}/src/main/resources</directory>
|
||||
<includes>
|
||||
<include>*.yml</include>
|
||||
<include>*.md</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<formats>
|
||||
<format>html</format>
|
||||
</formats>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>cobertura</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>inventive-repo</id>
|
||||
<url>http://repo.inventivetalent.org/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>http://repo.dmulloy2.net/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.minelink</groupId>
|
||||
<artifactId>CombatTagPlus</artifactId>
|
||||
<version>1.2.4-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.inventivetalent.npclib</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>1.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib-API</artifactId>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>vg.civcraft.mc.namelayer</groupId>
|
||||
<artifactId>NameLayer</artifactId>
|
||||
<version>2.8.03</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,17 @@
|
||||
rootProject.name = "simpleadminhacks"
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
maven {
|
||||
url = uri("https://maven.pkg.github.com/CivMC/CivGradle")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include(":paper")
|
||||
@@ -1,208 +0,0 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Base command handler that listens for the "hacks" command allowing CnC of all the loaded or unloaded hacks.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class CommandListener implements CommandExecutor {
|
||||
private SimpleAdminHacks plugin;
|
||||
|
||||
/**
|
||||
* Instantiate using static call
|
||||
*/
|
||||
public CommandListener() {
|
||||
this(SimpleAdminHacks.instance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate with provided plugin, useful for testing
|
||||
*/
|
||||
public CommandListener(SimpleAdminHacks plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures invocations of "hacks". Will attempt to command and control the various hacks as best as possible
|
||||
* based on that.
|
||||
*
|
||||
* @return true if command executed or should fail quietly, false if help should be displayed
|
||||
*/
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
|
||||
if (args.length == 0) {
|
||||
// display all hacks that are enabled.
|
||||
return showHacks(sender);
|
||||
} else if (args.length == 1) {
|
||||
// display a single hack
|
||||
return showHack(sender, args[0]);
|
||||
} else if (args.length == 2) {
|
||||
// enable/disable a hack
|
||||
return controlHack(sender, args[0], args[1]);
|
||||
} else if (args.length == 3) {
|
||||
// get a config
|
||||
return alterHack(sender, args[0], args[1], args[2], null);
|
||||
} else {
|
||||
// set a config
|
||||
return alterHack(sender, args[0], args[1], args[2], StringUtils.join(Arrays.copyOfRange(args, 3, args.length - 1), " "));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of all registered hacks and their status.
|
||||
*/
|
||||
private boolean showHacks(CommandSender sender) {
|
||||
if (plugin == null) return false;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(ChatColor.WHITE).append("List of hacks:\n");
|
||||
|
||||
for (SimpleHack<?> hack : plugin.getHacks()) {
|
||||
sb.append(" ")
|
||||
.append(ChatColor.AQUA).append(hack.getName())
|
||||
.append(ChatColor.WHITE).append(": ");
|
||||
if (hack.isEnabled()) {
|
||||
sb.append(ChatColor.GREEN).append("enabled");
|
||||
} else {
|
||||
sb.append(ChatColor.RED).append("disabled");
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
sender.sendMessage(sb.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal utility to get a hack from name.
|
||||
*/
|
||||
private SimpleHack<?> findHack(String hackName) {
|
||||
for (SimpleHack<?> candidate : plugin.getHacks()) {
|
||||
if (candidate.getName().equals(hackName)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show self-reported details from a single hack.
|
||||
*/
|
||||
private boolean showHack(CommandSender sender, String hackName) {
|
||||
if (plugin == null) return false;
|
||||
|
||||
SimpleHack<?> hack = findHack(hackName);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (hack == null) {
|
||||
sb.append(ChatColor.AQUA).append(hackName).append(ChatColor.WHITE).append(" not found.");
|
||||
} else {
|
||||
sb.append(ChatColor.WHITE).append("Self-reported details from hack ")
|
||||
.append(ChatColor.AQUA).append(hackName).append(ChatColor.WHITE).append(":\n")
|
||||
.append(ChatColor.GRAY).append(hack.status());
|
||||
}
|
||||
|
||||
sender.sendMessage(sb.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable a hack.
|
||||
*/
|
||||
private boolean controlHack(CommandSender sender, String hackName, String control) {
|
||||
if (plugin == null || hackName == null || control == null) return false;
|
||||
|
||||
if (!(control.equals("enable") || control.equals("disable"))) return false;
|
||||
|
||||
SimpleHack<?> hack = findHack(hackName);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (hack == null) {
|
||||
sb.append(ChatColor.AQUA).append(hackName).append(ChatColor.WHITE).append(" not found.");
|
||||
} else {
|
||||
sb.append(ChatColor.AQUA).append(hackName);
|
||||
if (control.equals("enable")) {
|
||||
if (hack.isEnabled()) {
|
||||
sb.append(ChatColor.GREEN).append(" is already enabled");
|
||||
} else {
|
||||
hack.softEnable();
|
||||
if (hack.isEnabled()) {
|
||||
sb.append(ChatColor.GREEN).append(" enabled successfully");
|
||||
} else {
|
||||
sb.append(ChatColor.RED).append(" failed to enable");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (hack.isEnabled()) {
|
||||
hack.softDisable();
|
||||
if (hack.isEnabled()) {
|
||||
sb.append(ChatColor.RED).append(" failed to disable");
|
||||
} else {
|
||||
sb.append(ChatColor.GREEN).append(" disabled successfully");
|
||||
}
|
||||
} else {
|
||||
sb.append(ChatColor.GREEN).append(" is already disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(sb.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the config within a hack.
|
||||
*/
|
||||
private boolean alterHack(CommandSender sender, String hackName, String control, String key, String value) {
|
||||
if (plugin == null || hackName == null || control == null || key == null) return false;
|
||||
|
||||
if (!(control.equals("get") || control.equals("set"))) return false;
|
||||
|
||||
SimpleHack<?> hack = findHack(hackName);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (hack == null) {
|
||||
sb.append(ChatColor.AQUA).append(hackName).append(ChatColor.WHITE).append(" not found.");
|
||||
} else {
|
||||
// We always get first.
|
||||
sb.append(ChatColor.AQUA).append(hackName);
|
||||
sb.append(" : ").append(ChatColor.BLUE).append(key).append(ChatColor.WHITE).append(" = ");
|
||||
Object currentValue = hack.config().get(key);
|
||||
if (currentValue == null) {
|
||||
sb.append(ChatColor.GRAY).append(" has no value");
|
||||
} else {
|
||||
sb.append(ChatColor.GOLD).append(currentValue.toString());
|
||||
}
|
||||
if (control.equals("set")) {
|
||||
// and optionally set.
|
||||
try {
|
||||
hack.config().set(key, value);
|
||||
sb.append("\n").append(ChatColor.WHITE).append(" set to = ")
|
||||
.append(ChatColor.GREEN).append(value);
|
||||
} catch (Exception e) {
|
||||
plugin.log(Level.WARNING, "Failed to set " + key + " to " + value + " in hack " + hackName, e);
|
||||
sb.append("\n").append(ChatColor.RED).append(" failed to set = ")
|
||||
.append(ChatColor.DARK_GREEN).append(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(sb.toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
public class InvalidConfigException extends RuntimeException {
|
||||
|
||||
public InvalidConfigException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidConfigException(String message, Throwable source) {
|
||||
super(message, source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
|
||||
/**
|
||||
* Wrapper for simple admin hacks, each doing a thing and each configurable.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class SimpleAdminHacks extends JavaPlugin {
|
||||
private static SimpleAdminHacks plugin;
|
||||
private SimpleAdminHacksConfig config;
|
||||
private List<SimpleHack<?>> hacks;
|
||||
|
||||
/**
|
||||
* No-op constructor
|
||||
*/
|
||||
public SimpleAdminHacks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deals with basic config processing, sets up global config and fires off
|
||||
* creation and registration of all hacks.
|
||||
*/
|
||||
public void onEnable() {
|
||||
SimpleAdminHacks.plugin = this;
|
||||
this.hacks = new LinkedList<SimpleHack<?>>();
|
||||
|
||||
// Config bootstrap
|
||||
this.saveDefaultConfig();
|
||||
this.reloadConfig();
|
||||
FileConfiguration conf = this.getConfig();
|
||||
try {
|
||||
this.config = new SimpleAdminHacksConfig(this, conf);
|
||||
} catch(InvalidConfigException e) {
|
||||
this.log(Level.SEVERE, "Failed to load config. Disabling plugin.", e);
|
||||
this.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Warning if no hacks.
|
||||
if (hacks == null || hacks.size() == 0) {
|
||||
this.log("No hacks enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Boot up the hacks.
|
||||
for (SimpleHack<?> hack : hacks) {
|
||||
hack.enable();
|
||||
}
|
||||
|
||||
this.registerCommand("hacks", new CommandListener(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards disable to hacks, clears instance and static variables
|
||||
*/
|
||||
public void onDisable() {
|
||||
if (hacks == null) return;
|
||||
for (SimpleHack<?> hack : hacks) {
|
||||
hack.disable();
|
||||
}
|
||||
hacks.clear();
|
||||
hacks = null;
|
||||
config = null;
|
||||
SimpleAdminHacks.plugin = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new SimpleHack.
|
||||
*/
|
||||
public void register(SimpleHack<?> hack) {
|
||||
if (hacks != null) {
|
||||
hacks.add(hack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters an existing SimpleHack.
|
||||
*/
|
||||
public void unregister(SimpleHack<?> hack) {
|
||||
if (hacks != null) {
|
||||
hacks.remove(hack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a wrapped version of hacks preventing external removal but allowing interaction with the hacks.
|
||||
*/
|
||||
public List<SimpleHack<?>> getHacks() {
|
||||
return Collections.unmodifiableList(hacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the psuedo-singleton instance of this plugin.
|
||||
*/
|
||||
public static SimpleAdminHacks instance() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overall config management for this plugin.
|
||||
*/
|
||||
public SimpleAdminHacksConfig config() {
|
||||
return config;
|
||||
}
|
||||
|
||||
// ===== debug / logging methods =====
|
||||
|
||||
private static final String debugPrefix = "[DEBUG] ";
|
||||
|
||||
public void debug(String message) {
|
||||
if (!config.isDebug()) return;
|
||||
log(Level.INFO, SimpleAdminHacks.debugPrefix + message);
|
||||
}
|
||||
|
||||
public void debug(String message, Object object) {
|
||||
if (!config.isDebug()) return;
|
||||
log(Level.INFO, SimpleAdminHacks.debugPrefix + message, object);
|
||||
}
|
||||
|
||||
public void debug(String message, Throwable thrown) {
|
||||
if (!config.isDebug()) return;
|
||||
log(Level.INFO, SimpleAdminHacks.debugPrefix + message, thrown);
|
||||
}
|
||||
|
||||
public void debug(String message, Object...objects) {
|
||||
if (!config.isDebug()) return;
|
||||
log(Level.INFO, SimpleAdminHacks.debugPrefix + message, objects);
|
||||
}
|
||||
|
||||
public void log(String message) {
|
||||
getLogger().log(Level.INFO, message);
|
||||
}
|
||||
|
||||
public void log(Level level, String message) {
|
||||
getLogger().log(level, message);
|
||||
}
|
||||
|
||||
public void log(Level level, String message, Throwable thrown) {
|
||||
getLogger().log(level, message, thrown);
|
||||
}
|
||||
|
||||
public void log(Level level, String message, Object object) {
|
||||
getLogger().log(level, message, object);
|
||||
}
|
||||
|
||||
public void log(Level level, String message, Object...objects) {
|
||||
getLogger().log(level, message, objects);
|
||||
}
|
||||
|
||||
// Other non-static convenience aides
|
||||
|
||||
public boolean serverHasPlugin(String pluginName) {
|
||||
return this.getServer().getPluginManager().isPluginEnabled(pluginName);
|
||||
}
|
||||
|
||||
// Broadcast aides
|
||||
|
||||
/**
|
||||
* Broadcast to all online players having the plugin's default broadcast permission
|
||||
*/
|
||||
public int serverBroadcast(String message) {
|
||||
return this.getServer().broadcast(message, config().getBroadcastPermission());
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast to all online players having the specified permission
|
||||
*/
|
||||
public int serverBroadcast(String message, String permission) {
|
||||
return this.getServer().broadcast(message, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast to all online operators.
|
||||
*/
|
||||
public int serverOperatorBroadcast(String message) {
|
||||
int cnt = 0;
|
||||
for( OfflinePlayer op : this.serverOperators()) {
|
||||
if (op.isOnline() && op.getPlayer() != null) {
|
||||
op.getPlayer().sendMessage(message);
|
||||
cnt ++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast to all online players.
|
||||
*/
|
||||
public int serverOnlineBroadcast(String message) {
|
||||
int cnt = 0;
|
||||
for (Player p : this.serverOnlinePlayers()) {
|
||||
if ( p != null && p.isOnline() ) {
|
||||
p.sendMessage(message);
|
||||
cnt ++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the Server Console
|
||||
*/
|
||||
public void serverSendConsoleMessage(String message) {
|
||||
this.serverConsoleSender().sendMessage(message);
|
||||
}
|
||||
|
||||
// Non-static Server accessor helps (facilitates testing)
|
||||
|
||||
public ConsoleCommandSender serverConsoleSender() {
|
||||
return this.getServer().getConsoleSender();
|
||||
}
|
||||
|
||||
public Collection<? extends Player> serverOnlinePlayers() {
|
||||
return this.getServer().getOnlinePlayers();
|
||||
}
|
||||
|
||||
public Set<OfflinePlayer> serverOperators(){
|
||||
return this.getServer().getOperators();
|
||||
}
|
||||
|
||||
public void registerListener(Listener listener) {
|
||||
this.getServer().getPluginManager().registerEvents(listener, this);
|
||||
}
|
||||
|
||||
public World serverGetWorld(String world) {
|
||||
World wurld = this.getServer().getWorld(world);
|
||||
if (world == null) {
|
||||
try {
|
||||
wurld = this.getServer().getWorld(UUID.fromString(world));
|
||||
} catch (IllegalArgumentException iae) {
|
||||
wurld = null; // not a UUID
|
||||
}
|
||||
}
|
||||
return wurld;
|
||||
}
|
||||
|
||||
// Safe Registration Wrapping
|
||||
|
||||
public void registerCommand(String command, CommandExecutor executor) {
|
||||
PluginCommand cmd = this.getCommand(command);
|
||||
if (cmd != null) {
|
||||
cmd.setExecutor(executor);
|
||||
} else {
|
||||
log(Level.WARNING, "Failed to register Executor for {0}, please define that command in the plugin.yml first.", command);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.CTAnnounceConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.HackBotConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.IntrobookConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.InvControlConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.NewfriendAssistConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.configs.ExperimentalConfig;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.hacks.CTAnnounce;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.hacks.HackBot;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.hacks.Introbook;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.hacks.InvControl;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.hacks.NewfriendAssist;
|
||||
import com.programmerdan.minecraft.simpleadminhacks.hacks.Experimental;
|
||||
|
||||
/**
|
||||
* Baseline configuration for SimpleAdminHacks and parser for all actual Hacks.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public class SimpleAdminHacksConfig {
|
||||
|
||||
private static int expected_config_level = 1;
|
||||
|
||||
private SimpleAdminHacks plugin;
|
||||
private ConfigurationSection config;
|
||||
|
||||
private boolean debug;
|
||||
private String broadcastPermission;
|
||||
|
||||
public SimpleAdminHacksConfig(ConfigurationSection root) {
|
||||
this(SimpleAdminHacks.instance(), root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new master Config based on the loaded config.
|
||||
*
|
||||
* @param plugin the Hacks master
|
||||
* @param root the configuration to use
|
||||
*/
|
||||
public SimpleAdminHacksConfig(SimpleAdminHacks plugin, ConfigurationSection root) {
|
||||
this.plugin = plugin;
|
||||
this.config = root;
|
||||
|
||||
int actual_config_level = config.getInt("configuration_file_version", -1);
|
||||
if (actual_config_level < 0 || actual_config_level > SimpleAdminHacksConfig.expected_config_level) {
|
||||
throw new InvalidConfigException("Invalid configuration file version");
|
||||
}
|
||||
|
||||
this.debug = config.getBoolean("debug", false);
|
||||
if (this.debug) {
|
||||
this.plugin.log("Debug messages enabled");
|
||||
}
|
||||
|
||||
this.broadcastPermission = config.getString("broadcast_permission", "simpleadmin.broadcast");
|
||||
if (this.debug) {
|
||||
this.plugin.log(Level.INFO, "broadcast_permission set to {0}", this.broadcastPermission);
|
||||
}
|
||||
|
||||
// Now load all the Hacks and register.
|
||||
ConfigurationSection hacks = config.getConfigurationSection("hacks");
|
||||
for (String key : hacks.getKeys(false)) {
|
||||
ConfigurationSection hack = hacks.getConfigurationSection(key);
|
||||
|
||||
// TODO eventually, replace this with reflection based load. For tonight, hack it.
|
||||
try {
|
||||
SimpleHack<?> newHack = bootstrapHack(hack);
|
||||
plugin.register(newHack);
|
||||
if (this.debug) {
|
||||
this.plugin.log(Level.INFO, "Registered a new hack: {0}", key);
|
||||
}
|
||||
} catch (InvalidConfigException ice) {
|
||||
this.plugin.log(Level.WARNING, key + " could not be mapped to a Hack, config values problem", ice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
public void setDebug(boolean mode) {
|
||||
this.debug = mode;
|
||||
update("debug", mode);
|
||||
}
|
||||
|
||||
protected void update(String node, Object value) {
|
||||
config.set(node, value);
|
||||
plugin.saveConfig();
|
||||
}
|
||||
|
||||
public String getBroadcastPermission() {
|
||||
return this.broadcastPermission;
|
||||
}
|
||||
|
||||
private SimpleHack<?> bootstrapHack(ConfigurationSection boot) {
|
||||
String hackName = boot.getString("name");
|
||||
if (hackName == null) {
|
||||
throw new InvalidConfigException("Hack stubbed but config lacks a name, cannot determine which hack to load");
|
||||
}
|
||||
|
||||
try {
|
||||
if (hackName.equals(CTAnnounce.NAME)) {
|
||||
return new CTAnnounce(this.plugin, new CTAnnounceConfig(this.plugin, boot));
|
||||
} else if (hackName.equals(NewfriendAssist.NAME)) {
|
||||
return new NewfriendAssist(this.plugin, new NewfriendAssistConfig(this.plugin, boot));
|
||||
} else if (hackName.equals(Introbook.NAME)) {
|
||||
return new Introbook(this.plugin, new IntrobookConfig(this.plugin, boot));
|
||||
} else if (hackName.equals(HackBot.NAME)) {
|
||||
return new HackBot(this.plugin, new HackBotConfig(this.plugin, boot));
|
||||
} else if (hackName.equals(InvControl.NAME)) {
|
||||
return new InvControl(this.plugin, new InvControlConfig(this.plugin, boot));
|
||||
} else if (hackName.equals(Experimental.NAME)) {
|
||||
return new Experimental(this.plugin, new ExperimentalConfig(this.plugin, boot));
|
||||
}
|
||||
} catch (InvalidConfigException ice) {
|
||||
plugin.log(Level.WARNING, "Failed to activate " + hackName + " hack");
|
||||
}
|
||||
|
||||
throw new InvalidConfigException("Claimed to be a viable hack but isn't: " + hackName);
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
/**
|
||||
* Baseline structure for a managed hack.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public abstract class SimpleHack<T extends SimpleHackConfig> {
|
||||
/**
|
||||
* Why store a reference to the plugin? Largely this is for unit test combatibility (to avoid too many static references)
|
||||
* but it also allows us to do either, including static dependency injection on demand.
|
||||
*
|
||||
* Visibility is set such that subclasses must use the accessor.
|
||||
*/
|
||||
private SimpleAdminHacks plugin;
|
||||
|
||||
/**
|
||||
* Protected so that subclasses can directly reference; this is the config for the hack as extracted
|
||||
* by the managing plugin's configuration parsing infrastructure.
|
||||
*
|
||||
* Using generics so each Hack can more concretely specify the nature of their config.
|
||||
*/
|
||||
protected T config;
|
||||
|
||||
/**
|
||||
* Captures baseline requirements of the plugin and the config for this hack.
|
||||
*/
|
||||
public SimpleHack(SimpleAdminHacks plugin, T config) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either class-local or static instance of this plugin, depending on what is available.
|
||||
*/
|
||||
public SimpleAdminHacks plugin() {
|
||||
if (this.plugin == null) {
|
||||
this.plugin = SimpleAdminHacks.instance();
|
||||
}
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables this hack by calling:
|
||||
* <ul>
|
||||
* <li> {@link #dataBootstrap}
|
||||
* <li> {@link #registerCommands}
|
||||
* <li> {@link #registerListeners}
|
||||
* </ul>
|
||||
*/
|
||||
public void enable() {
|
||||
dataBootstrap();
|
||||
registerCommands();
|
||||
registerListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Any listeners that this hack needs should get registered here.
|
||||
*/
|
||||
public abstract void registerListeners();
|
||||
|
||||
/**
|
||||
* If this hack has its own commands, register them here.
|
||||
*/
|
||||
public abstract void registerCommands();
|
||||
|
||||
/**
|
||||
* If this hack uses data structures n' such, it is preferred to configure them here instead of the constructor.
|
||||
*/
|
||||
public abstract void dataBootstrap();
|
||||
|
||||
/**
|
||||
* Disables this hack by calling:
|
||||
* <ul>
|
||||
* <li> {@link #unregisterListeners}
|
||||
* <li> {@link #unregisterCommands}
|
||||
* <li> {@link #dataCleanup}
|
||||
* </ul>
|
||||
* Then discarding the plugin and config references.
|
||||
*/
|
||||
public void disable() {
|
||||
unregisterListeners();
|
||||
unregisterCommands();
|
||||
dataCleanup();
|
||||
|
||||
this.config = null;
|
||||
this.plugin = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for "soft" disabling this hack.
|
||||
*/
|
||||
public void softDisable() {
|
||||
this.config.setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for "soft" enabling this hack.
|
||||
*/
|
||||
public void softEnable() {
|
||||
this.config.setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience passthrough wrapper for config.isEnabled();
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return this.config == null ? false : this.config.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience passhthrough wrapper for config.getName();
|
||||
*/
|
||||
public String getName() {
|
||||
return this.config == null ? null : this.config.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for config externally.
|
||||
*/
|
||||
public SimpleHackConfig config() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically optional. For full completeness you could define this. All of the plugin's registered listeners are
|
||||
* unregistered during disable, however, at the Spigot level.
|
||||
*/
|
||||
public abstract void unregisterListeners();
|
||||
|
||||
/**
|
||||
* Also optional; command handlers will likewise be sorted on plugin disable. Fill this out if you intend for
|
||||
* this hack's custom command handling to be off if only this hack is disabled.
|
||||
*/
|
||||
public abstract void unregisterCommands();
|
||||
|
||||
/**
|
||||
* Not optional; any data structures, connections, or temporary files should get cleaned up here.
|
||||
*/
|
||||
public abstract void dataCleanup();
|
||||
|
||||
/**
|
||||
* Not optional; customized status for this SimpleHack for display in CnC
|
||||
*/
|
||||
public abstract String status();
|
||||
|
||||
/**
|
||||
* Simple name equality. Don't have two hacks with the same name please.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object e) {
|
||||
if (e != null && e instanceof SimpleHack) {
|
||||
SimpleHack<?> f = (SimpleHack<?>) e;
|
||||
if (f.config != null && this.config != null && f.config.getName().equals(this.config.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
package com.programmerdan.minecraft.simpleadminhacks;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* Simple config shell that assumes a {@link ConfigurationSection} as a base.
|
||||
*
|
||||
* @author ProgrammerDan
|
||||
*/
|
||||
public abstract class SimpleHackConfig {
|
||||
|
||||
private SimpleAdminHacks plugin;
|
||||
private ConfigurationSection base;
|
||||
private String name;
|
||||
private boolean enabled;
|
||||
|
||||
/**
|
||||
* Constructor that sets the internal config section. That base config is not visible
|
||||
* outside of this class or its subclasses.
|
||||
*
|
||||
* Also extracts the one shared element of all hack configs, the "name" of the hack.
|
||||
*
|
||||
* Calls {@link #wireup(ConfigurationSection)}
|
||||
*/
|
||||
public SimpleHackConfig(SimpleAdminHacks plugin, ConfigurationSection base) {
|
||||
this.plugin = plugin;
|
||||
this.base = base;
|
||||
this.name = base.getString("name");
|
||||
this.enabled = base.getBoolean("enabled", false);
|
||||
plugin.log(Level.INFO, "Config for {0}, enabled set to {1}", this.name, this.enabled);
|
||||
this.wireup(base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should override this method.
|
||||
*/
|
||||
protected abstract void wireup(ConfigurationSection config);
|
||||
|
||||
/**
|
||||
* Might be useful in some situations for subclasses to directly access the
|
||||
* stored base config.
|
||||
*/
|
||||
public ConfigurationSection getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
protected SimpleAdminHacks plugin() {
|
||||
if (this.plugin == null) {
|
||||
return SimpleAdminHacks.instance();
|
||||
} else {
|
||||
return this.plugin;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for base config's set, for use with the hacks command
|
||||
*/
|
||||
public void set(String attr, Object value) {
|
||||
if (this.base != null && attr != null) {
|
||||
base.set(attr, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for base config's get, for use with the hacks command
|
||||
*/
|
||||
public Object get(String attr) {
|
||||
if (this.base != null && attr != null) {
|
||||
return base.get(attr);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 108 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user