Compare commits

...
132 Commits
Author SHA1 Message Date
NotAlexNoyle 2d5b6beef3 Point submodules at canonical Gitea repositories 2026-11-01 12:49:12 -05:00
NotAlexNoyle 2f91860ad9 Update canonical Gitea links 2026-10-31 11:49:12 -04:00
NotAlexNoyle 4ae8786e8e Update canonical Gitea links 2026-10-29 09:18:40 -04:00
NotAlexNoyle 60e0b41186 Exclude CODEOWNERS from language statistics 2026-10-28 15:32:13 -04:00
NotAlexNoyle 4632d61b96 Add CODEOWNERS (one staff approval) 2026-10-28 15:32:13 -04:00
NotAlexNoyle 03b955fd2a Update Utilities-OG API 2026-10-18 15:02:25 -04:00
NotAlexNoyle 8d04fc0cf7 Update Utilities-OG 2026-09-14 02:01:35 -04:00
NotAlexNoyle 64d652a676 Remove Dynamap 2026-08-11 14:33:00 -04:00
NotAlexNoyle 31bc05689d Fix Dynmap repo 2026-08-11 14:28:50 -04:00
NotAlexNoyle 3dee6ed808 Update Utilities-OG API 2026-07-20 00:50:02 -04:00
NotAlexNoyle 280063a609 Remove Template-OG artifact 2026-06-21 21:03:20 -04:00
NotAlexNoyle 8a84095afe Update Utilities-OG API 2026-05-20 11:22:37 -04:00
NotAlexNoyle 3fcdfee824 Update Utilities-OG 2026-05-10 14:19:57 -04:00
NotAlexNoyle eb4f80f467 Fix ProtocolLib vanishing 2026-04-22 15:00:28 -04:00
NotAlexNoyle 055e4393d4 Update Vanish-OG 2026-04-22 13:38:35 -04:00
NotAlexNoyle 14e784a7ea Fix vanish persistence 2026-04-22 11:20:07 -04:00
NotAlexNoyle ad2af065f4 Revert failed keydb migration 2026-04-22 08:29:35 -04:00
NotAlexNoyle 34ff8e7443 Force clear past vanish states in other plugins 2026-04-22 07:58:44 -04:00
NotAlexNoyle d56c34fdd6 Fix stale keydb entries on login 2026-04-22 06:48:56 -04:00
NotAlexNoyle f697333710 Fix stale vanish states 2026-04-21 16:09:17 -04:00
NotAlexNoyle a01c07f641 Fix invalid vanish states 2026-04-21 15:13:48 -04:00
NotAlexNoyle 74bda649a5 Fix old invalid vanish states 2026-04-21 15:01:38 -04:00
NotAlexNoyle c685d4ccfa Fix TAB-OG compatibility 2026-04-21 14:30:36 -04:00
NotAlexNoyle 40ef184e3a Fix TAB-OG vanished hook 2026-04-21 14:17:10 -04:00
NotAlexNoyle aadf6cc622 Fix everyone being invisible 2026-04-21 13:53:32 -04:00
NotAlexNoyle e2947d30db Update OpenInv hook 2026-04-21 11:34:14 -04:00
NotAlexNoyle fc9afdf09a Fix TAB-OG support with ViaSuite and forge clients 2026-04-21 10:53:48 -04:00
NotAlexNoyle d1d0fd2eb2 Fix TAB-OG Hooks 2026-04-21 06:03:20 -04:00
NotAlexNoyle a3a118ee11 Use TAB-OG API instead of playerdata for setting vanish status 2026-04-20 12:46:25 -04:00
NotAlexNoyle 6f6296971d Add TAB-OG Compatibility 2026-04-20 11:10:15 -04:00
NotAlexNoyle a8f257ae62 Update Utilities-OG API 2026-04-20 02:14:15 -04:00
NotAlexNoyle c0107a99d4 Fix runtime exception 2026-04-15 05:57:02 -04:00
NotAlexNoyle cf4db3f5ba Fix ProtocolLib 1.19.4 compatibility 2026-04-14 15:07:50 -04:00
NotAlexNoyle dfffb9c154 Fix SLF4J errors 2026-04-14 14:08:01 -04:00
NotAlexNoyle 98bd470968 Fix SLF4J warning 2026-04-13 04:32:26 -04:00
NotAlexNoyle 0abb3fcb9a Fix gradle placeholder expansion 2026-04-13 04:28:31 -04:00
NotAlexNoyle c3b22df4f6 Avoid keydb parsing bugs 2026-04-13 03:37:52 -04:00
NotAlexNoyle 5bf3e2def8 1.1 - Store data using lettuce instead of data.yml 2026-04-13 03:29:35 -04:00
NotAlexNoyle ff4118bb4e Make directories generic 2026-04-08 13:31:38 -04:00
NotAlexNoyle 5b11813ff7 Release Vanish-OG 2026-04-08 07:53:46 -04:00
Leon Mangler 84627afee6 6.2.21:
- Improve player hiding API and performance
- Add OpenInv hook
- Various improvements and fixes
2025-08-19 21:26:25 +09:00
Leon Mangler 46b0581005 Update README.md 2024-08-03 07:31:14 +02:00
Leon Mangler aaa15b93c3 Merge pull request #88 from Learting/patch-1
Support Purpur
2024-08-03 07:22:57 +02:00
Leon Mangler e2526f8f01 6.2.20:
- Only display warning for failed tab-complete interceptions
2024-08-03 14:15:45 +09:00
Learting b6c44164f6 Support Purpur 2024-07-10 09:16:40 +02:00
Learting d960e23fc5 Support Purpur 2024-07-10 09:05:10 +02:00
Leon Mangler bcf10d0688 6.2.19:
- Redo night vision module without packets
- Fix version util on latest paper
2024-06-26 00:10:26 +09:00
Leon Mangler acf4242ab8 Update Lombok and fix compile 2024-03-25 15:38:30 +09:00
Leon Mangler 5bfd192d97 Fix compile 2024-03-25 15:33:42 +09:00
Leon Mangler e133f70b86 Avoid storing the player reference in VanishPlayer 2024-03-25 15:31:47 +09:00
Leon Mangler fbc303bbee Increase java version to 17 to fulfill paper dependency requirements 2023-11-06 15:53:22 +09:00
Leon Mangler df72b954c4 Fix maven build by changing spigot to paper repo 2023-11-06 15:41:11 +09:00
Leon Mangler 086278d662 Merge branch 'crazycat256-paper' 2023-08-13 18:22:38 +09:00
Leon Mangler a9b9770233 Bump version to 6.2.18 2023-08-13 18:18:56 +09:00
Leon Mangler 9065c44d9e Improve performance of NoMobSpawn 2023-08-13 18:14:15 +09:00
Leon Mangler 794d34d0df Improve error logging in new features 2023-08-13 18:07:10 +09:00
Leon Mangler d5777add02 Fix typo 2023-08-13 18:00:46 +09:00
Leon Mangler 77653f48c2 Add PaperServerPingListener 2023-08-13 18:00:31 +09:00
Leon Mangler 843e4d6ee1 Fix server list ping write position and improve error messages 2023-08-13 17:51:26 +09:00
Leon Mangler 48fd17a36d Merge branch 'paper' of github.com:crazycat256/SuperVanish into crazycat256-paper 2023-08-13 17:45:37 +09:00
Leon Mangler d846cd5519 Merge pull request #79 from crazycat256/externalinvisibility
Bug fixes
2023-08-04 11:22:34 +02:00
crazycat256 5da1b96e20 Create NoMobSpawn.java 2023-08-01 23:57:55 +02:00
crazycat256 9e60483c78 Create HideAdvancementMessages.java 2023-08-01 23:57:52 +02:00
crazycat256 f5c20777eb Add features to config.yml 2023-08-01 23:57:48 +02:00
crazycat256 6b36ea7d8f Add paperServer featureInfo 2023-08-01 23:57:10 +02:00
crazycat256 7fdfde4523 Switch to PaperMC API 2023-08-01 23:56:24 +02:00
crazycat256 5a51918af1 Add CALIBRATED_SCULK_SENSOR 2023-08-01 19:25:09 +02:00
crazycat256 696e762fbd Fix External Invisibility 2023-07-30 22:36:21 +02:00
Leon Mangler 8d7f3d6da5 6.2.17: Update for MC 1.20.1 2023-06-29 18:31:59 +09:00
Leon Mangler bf765d8055 Bump version to 6.2.16 2023-05-18 19:31:31 +09:00
Leon Mangler ee6ad93f5c Only log errors once in TabCompleteListener to prevent spam 2023-05-18 18:50:21 +09:00
Leon Mangler b2e39dd9af Remove Citizens dependency to resolve circular dependency issues 2023-04-19 20:49:59 +09:00
Leon Mangler b649d0f1e2 Increase teleport distance when closing chest silently 2023-02-06 20:13:09 +01:00
Leon Mangler f67dd7bce3 Fix comment 2023-01-28 21:33:55 +01:00
Leon Mangler 5671730d22 Bump version to 6.2.15 2023-01-28 21:30:29 +01:00
Leon Mangler ef49346fca Merge pull request #71 from crazycat256/master
Add check for sculk sensors, sculk shrieker and turtle eggs
2023-01-28 21:28:20 +01:00
Leon Mangler 4954745ceb Prevent falling into the ground when opening chests silently 2023-01-28 21:14:38 +01:00
crazycat256 215b2dbe83 Merge branch 'LeonMangler:master' into master 2023-01-19 21:45:54 +01:00
Leon Mangler 19d82a11d9 Bump version to 6.2.14 2023-01-19 18:21:10 +01:00
Leon Mangler 23f3952a6b Fix hex colors again 2023-01-19 18:15:47 +01:00
Leon Mangler 12ddb16175 6.2.13:
- 1.19.3 update
- Disabled some unstable features
- Added vanish prefix and suffix placeholders
2023-01-19 18:08:49 +01:00
crazycat256 cb41cfe553 Merge branch 'LeonMangler:master' into master 2022-12-04 12:27:52 +01:00
Leon Mangler 4f0612b338 Fix &#FFFFFF chat color format 2022-11-28 23:19:56 +01:00
Leon Mangler e9e50e2b5e Fix null pointer exception in sendMessage(..) 2022-11-28 23:18:57 +01:00
crazycat256 4f48b825f6 Removed debug message 2022-11-15 21:49:49 +01:00
crazycat256 91019a2c40 Added NoRaidTrigger feature 2022-11-15 21:45:36 +01:00
crazycat256 29e082dc94 Added NoTurtleEggBreaking feature 2022-11-03 17:20:45 +01:00
crazycat256 91999ea0ce Update NoSculkSensorDetection.java 2022-11-03 10:54:52 +01:00
Leon Mangler afbb1348ae Bump version to 6.2.12 2022-08-29 23:59:14 +02:00
Leon Mangler d1f579894d Add TabCompleteModule to intercept tab complete packets 2022-08-29 23:58:49 +02:00
Leon Mangler 937d14a08d git push origin masterMerge branch 'ARR4NN-master' 2022-08-19 22:48:12 +02:00
Leon Mangler bc1231cd81 Bump version to 6.2.11 2022-08-19 22:47:49 +02:00
Leon Mangler 3c5afcc030 Fix oneDotSeventeenOrHigher feature requirement 2022-08-19 22:46:53 +02:00
Leon Mangler b79d4bd628 Add some more checks and fix formatting in drip leaf feature 2022-08-19 22:46:35 +02:00
ARR4NN b41a82d533 Simplify 2022-08-17 10:31:26 +01:00
ARR4NN 48f2f6f3c8 Add check for tilting of DripLeaves. 2022-08-17 10:22:34 +01:00
Leon Mangler c4c889d432 Remove double isSneaking check 2022-08-12 04:42:09 +02:00
Leon Mangler 620a98d1cf Merge pull request #67 from BetTD/pr
Remove unnecessary checks and enable resource filtering
2022-08-12 04:40:04 +02:00
Leon Mangler e1702994b0 Fix config version number change 2022-08-12 04:35:47 +02:00
Leon Mangler 5cb1c11f0e Use lambda expressions in FeatureMgr 2022-08-12 04:34:21 +02:00
Leon Mangler 4f7cc7bad7 Update sculk sensor config setting name 2022-08-12 04:32:26 +02:00
Leon Mangler f61cdd6b0e Merge pull request #68 from BetTD/no-sculk-sensor-detect
Add ability to disable sculk sensor detection for vanished players
2022-08-12 04:29:11 +02:00
Raúl M 9212ad99ff Re-added nullcheck for p.getItemInHand() 2022-08-12 04:05:35 +02:00
Raúl M 5d7b4c09d6 Merge branch 'master' of https://github.com/LeonMangler/SuperVanish into pr
 Conflicts:
	src/main/resources/config.yml
	src/main/resources/messages.yml
	src/main/resources/plugin.yml
2022-08-12 04:02:08 +02:00
Raúl M 3eb9e625ea Undo changes in 6.2.10 2022-08-12 03:59:48 +02:00
Raúl M 96ac8d63a6 Merge branch 'master' of https://github.com/LeonMangler/SuperVanish into no-sculk-sensor-detect
 Conflicts:
	src/main/resources/config.yml
2022-08-12 03:58:14 +02:00
Leon Mangler 0f6728220a 6.2.10: Add sculk sensor activate listener 2022-08-02 23:56:28 +02:00
Leon Mangler e3270fbc51 Turn night vision back on again 2022-08-02 23:55:36 +02:00
Raúl M 2555593fa6 Enable resource filtering for config.yml and messages.yml 2022-07-10 20:37:22 +02:00
Raúl M 2781e3d599 Merge branch 'master' of https://github.com/LeonMangler/SuperVanish into pr
 Conflicts:
	src/main/resources/plugin.yml
2022-07-10 20:36:36 +02:00
Leon Mangler 205e7a2d4d 6.2.9: Fix NightVision 2022-07-09 00:35:27 +02:00
Raúl M a93764355f Add ability to disable sculk sensor detection for vanished players 2022-07-07 20:49:15 +02:00
Raúl M 62c095d9a2 Implement resource filtering 2022-07-07 20:20:25 +02:00
Raúl M c7b983c1ff Remove unnecessary checks 2022-07-07 20:02:36 +02:00
Leon Mangler 65ceba4708 6.2.8: Experimental 1.19 update 2022-06-30 22:27:32 +02:00
Leon Mangler 333837ccea Improve TabCompleteListener performance 2022-05-17 19:50:14 +02:00
Leon Mangler 85d20e17d3 Merge remote-tracking branch 'svgithubrepo/master' 2022-03-15 22:31:00 +01:00
Leon Mangler 1ad76d43dc Update NightVision and bump to 6.2.7 2022-03-15 22:30:43 +01:00
Leon Mangler c2366d3013 Bump version to 6.2.7 2022-03-15 22:22:02 +01:00
Leon Mangler f57056a13a Update ProtocolLib dependency 2022-01-18 16:10:30 +01:00
Leon Mangler 2ccec38b65 Remove SuperTrails hook from plugin.yml and config.yml 2022-01-18 16:02:11 +01:00
Leon Mangler ca4287dcf5 Update maven repo info in README 2022-01-18 15:59:29 +01:00
Leon Mangler b1c3cf280f Update dynmap hook and pom.xml to remove local dependencies 2022-01-18 15:57:36 +01:00
Leon Mangler a1cc8e9cfb Remove SuperTrails hook 2022-01-18 15:57:07 +01:00
Leon Mangler b2873319dc Update maven repository info in README.md 2021-10-04 20:00:22 +02:00
Leon Mangler 1effcc0d87 Bump version in maven 2021-10-04 19:58:04 +02:00
Leon Mangler bf05c51d3d Merge pull request #62 from montlikadani/patch-1
Changing repository urls from HTTP to HTTPS for security reasons
2021-10-04 19:48:01 +02:00
montlikadani 6c3adbcd40 Changing from HTTP to HTTPS for security reasons 2021-09-04 21:05:46 +02:00
Leon Mangler 24d6d2d2b2 Accept '&' before HEX color placeholders 2021-08-13 19:57:26 +02:00
Leon Mangler f1eea4626e Update Lombok dependency as well 2021-08-13 19:56:42 +02:00
Leon Mangler 6e637ca5c8 Merge pull request #61 from Iaiao/patch-2
Bump lombok version to 1.18.20
2021-08-13 19:55:40 +02:00
Iaiao eb3145daa6 Bemp lombok version to 1.18.20 2021-08-07 20:46:27 +03:00
114 changed files with 7122 additions and 2400 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
.gitea/CODEOWNERS linguist-detectable=false
+3
View File
@@ -0,0 +1,3 @@
# Pull requests request review from the eligible staff team(s).
# One approval from either an Admin or Developer satisfies branch protection.
* @trueog/Admins @trueog/Developers
+6 -1
View File
@@ -1,6 +1,12 @@
*.class
target/
out/
build/
.gradle/
bin/
.classpath
.project
.checkstyle
# Mobile Tools for Java (J2ME)
.mtj.tmp/
@@ -10,7 +16,6 @@ out/
*.eml
*.iml
# Eclipse files
.settings
-34
View File
@@ -1,34 +0,0 @@
image: maven:3-jdk-9-slim
cache:
paths:
- .m2/repository
variables:
MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
stages:
- build
- deploy
build:
stage: build
script:
- apt update
- apt install wget -y
- wget https://gitlab.com/cubekrowd/mavenrepo/raw/master/build2.sh
- bash build2.sh
artifacts:
paths:
- "*.jar"
deploy:
stage: deploy
script:
- apt update
- apt install wget -y
- wget https://gitlab.com/cubekrowd/mavenrepo/raw/master/deploy1.sh
- bash deploy1.sh
only:
- master
+3
View File
@@ -0,0 +1,3 @@
[submodule "libs/Utilities-OG"]
path = libs/Utilities-OG
url = https://git.trueog.net/trueog/Utilities-OG
+155 -20
View File
@@ -1,27 +1,162 @@
# SuperVanish
Website: https://www.spigotmc.org/resources/supervanish-be-invisible.1331/
# Vanish-OG
Bukkit-Plugin for Spigot/CraftBukkit (modded Minecraft server)
A fork of [SuperVanish](https://www.spigotmc.org/resources/supervanish-be-invisible.1331/) for [TrueOG Network](https://trueog.net). Lets staff become completely invisible so they can quietly observe and moderate.
Allows server admins to be completely invisible and undetectable for other players, which helps them with their administrative work.
Built for **Purpur 1.19.4**. Clients from **Minecraft 1.8 through 1.21.11** can connect through ViaSuite (ViaVersion / ViaBackwards / ViaRewind) and vanish works correctly across the board.
Feel free to create Pull Requests if you'd like to improve SuperVanish! Please report issues on SpigotMC via PM!
### What's different from SuperVanish?
## Maven Repository
- **Tab list hiding works on 1.19+** Upstream switched it off after a Mojang change broke it. Vanish-OG handles the new format so vanished staff stay hidden from the tab list.
- **Spectator indication works on 1.19.4 again.** `MarkVanishedPlayersAsSpectators` now uses the native 1.19.4 player info update packet, so staff who can see vanished players still get the dark-gray/head-only tab list cue across Via-served 1.8-1.21.11 clients.
- **Silent chest opening works on 1.19.4 again.** Peeking into containers looks completely invisible to other players if vanished.
- **All connected clients see the same thing.** Whether someone joins from 1.8 or the latest 1.21.11 release through ViaSuite, vanish behaves identically.
- **[Chat-OG](https://git.trueog.net/trueog/Chat-OG) owns announcement visibility.** Vanish-OG no longer rewrites join/quit, death, or advancement messages and no longer emits fake join/quit broadcasts on vanish toggles. Chat-OG is responsible for hiding vanished-player activity from Discord-facing announcements.
- **OpenInv support.** If installed, Vanish-OG hands off chest viewing to OpenInv so staff never enter spectator mode and can't get stuck there after a crash.
- **MiniPlaceholders support** (via Utilities-OG) for use in chat, tab, and hologram plugins.
- **Safer chest peeking.** Staff no longer occasionally fall through the floor when finishing a peek. Pair with [WGamemode](https://github.com/true-og/WGamemode) to auto-restore gamemodes after crashes if OpenInv is not installed.
- **Flat-file storage again.** Vanish state and player preferences are stored locally in `plugins/Vanish-OG/data.yml`, which keeps the runtime path simple and removes the external KeyDB dependency.
- **Rejoin state is persisted, not permission-driven.** Players only reconnect vanished if `data.yml` still marks them vanished from last time; there is no "always join vanished" permission path anymore.
- **TAB-OG compatibility via TAB API.** When [TAB-OG](https://git.trueog.net/trueog/TAB-OG) is installed, Vanish-OG registers a `VanishIntegration` handler with TAB's API so TAB consults Vanish-OG's state manager directly for its `canSee()` / `isVanished()` checks instead of depending solely on the `"vanished"` player metadata key. This closes the join-time race where Forge clients crashed because TAB evaluated tab-list visibility before the metadata was set. The metadata key is still set during `PlayerLoginEvent` so TAB's placeholder-level `isVanished` fallback and any other plugin using the convention keep working.
- **Removed old clutter.** Deprecated functions are removed and the code is updated for java 17 conventions.
### Chat-OG handles some events that used to be handled by SuperVanish
If your stack includes [Chat-OG](https://git.trueog.net/trueog/Chat-OG), think of the split like this:
- Vanish-OG manages vanish state, player/entity visibility, tab list hiding, spectator indication, and silent chest behavior.
- Chat-OG manages whether vanished-player join/quit, kick, advancement, death, and Discord bridge announcements are surfaced.
This avoids two plugins trying to suppress or fake the same announcement events.
### API
Vanish-OG ships the same Bukkit-facing API package as SuperVanish: `de.myzelyam.api.vanish`.
### Main entry point
Use [`VanishAPI`](src/main/java/de/myzelyam/api/vanish/VanishAPI.java) for all direct integrations.
```java
import de.myzelyam.api.vanish.VanishAPI;
import net.trueog.utilitiesog.UtilitiesOG;
```
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<!-- SuperVanish -->
<dependency>
<groupId>com.github.LeonMangler</groupId>
<artifactId>SuperVanish</artifactId>
<version>6.2.1</version>
</dependency>
</dependencies>
### Commands
Main command: `/vanish` (also `/v`, `/sv`, `/supervanish`).
### State queries
- `VanishAPI.getInvisiblePlayers()`
Returns the UUIDs of all online vanished players.
- `VanishAPI.getAllInvisiblePlayers()`
Returns the UUIDs of all vanished players, including offline players stored in `data.yml`.
- `VanishAPI.isVanished(Player player)`
Checks if a player is vanished. Returns `boolean`.
- `VanishAPI.isVanished(UUID uuid)`
Checks if a player is vanished. Returns `boolean`.
Java:
```java
if (VanishAPI.isVanished(player) || VanishAPI.isVanished(player.getUniqueId())) {
UtilitiesOG.trueogMessage(player, "You are vanished.");
}
```
Kotlin:
```kotlin
if (VanishAPI.isVanished(player) || VanishAPI.isVanished(player.uniqueId)) {
UtilitiesOG.trueogMessage(player, "You are vanished.")
}
```
### Visibility control
- `VanishAPI.hidePlayer(Player player)`
Vanishes the player through the normal SuperVanish pipeline and fires the related events. Main thread only.
- `VanishAPI.showPlayer(Player player)`
Reveals the player through the normal SuperVanish pipeline and fires the related events. Main thread only.
- `VanishAPI.canSee(Player viewer, Player viewed)`
Returns whether `viewer` should currently be able to see `viewed`. Main thread only.
Java:
```java
if (!VanishAPI.canSee(viewer, target)) {
UtilitiesOG.trueogMessage(viewer, "<red>That player is hidden from you.");
}
VanishAPI.hidePlayer(target);
VanishAPI.showPlayer(target);
```
Kotlin:
```kotlin
if (!VanishAPI.canSee(viewer, target)) {
UtilitiesOG.trueogMessage(viewer, "<red>That player is hidden from you.")
}
VanishAPI.hidePlayer(target)
VanishAPI.showPlayer(target)
```
### Configuration access
- `VanishAPI.getConfiguration()`
Returns `config.yml`. Main thread only; treat the returned `FileConfiguration` as Bukkit-owned mutable state.
- `VanishAPI.getMessages()`
Returns `messages.yml`. Main thread only; treat the returned `FileConfiguration` as Bukkit-owned mutable state.
- `VanishAPI.reloadConfig()`
Reloads the plugin. Main thread only.
- `VanishAPI.getPlugin()`
Returns the active `SuperVanish` plugin instance. Fetching the reference is cheap, but any interaction with the plugin or Bukkit APIs should stay on the main thread.
### Events
The API exposes the following Bukkit events in `de.myzelyam.api.vanish`:
All of these are normal Bukkit events and should be handled on the main server thread. Do not assume they fire asynchronously.
- [`PlayerHideEvent`](src/main/java/de/myzelyam/api/vanish/PlayerHideEvent.java)
Fired before a player is hidden. Cancellable. Includes `isSilent()` / `setSilent(boolean)`.
- [`PostPlayerHideEvent`](src/main/java/de/myzelyam/api/vanish/PostPlayerHideEvent.java)
Fired after a player has been hidden. Not cancellable. Includes `isSilent()`.
- [`PlayerShowEvent`](src/main/java/de/myzelyam/api/vanish/PlayerShowEvent.java)
Fired before a player is shown. Cancellable. Includes `isSilent()` / `setSilent(boolean)`.
- [`PostPlayerShowEvent`](src/main/java/de/myzelyam/api/vanish/PostPlayerShowEvent.java)
Fired after a player has been shown. Not cancellable. Includes `isSilent()`.
- [`PlayerVanishStateChangeEvent`](src/main/java/de/myzelyam/api/vanish/PlayerVanishStateChangeEvent.java)
Fired when persisted vanish state changes for a UUID. Cancellable. Exposes `isVanishing()`, `getUUID()`, `getPlayer()` (returns the Bukkit `Player` or `null` if offline), `getName()`, and `getCause()`. Constructible via `(UUID, String, boolean, String)` or `(Player, boolean, String)`.
### Example listener
Java:
```java
@EventHandler
public void onPlayerHide(PlayerHideEvent event) {
if (!event.getPlayer().hasPermission("myplugin.allowvanish")) {
UtilitiesOG.trueogMessage(event.getPlayer(), "<red>You are not allowed to vanish.");
event.setCancelled(true);
}
}
```
Kotlin:
```kotlin
@EventHandler
fun onPlayerHide(event: PlayerHideEvent) {
if (!event.player.hasPermission("myplugin.allowvanish")) {
UtilitiesOG.trueogMessage(event.player, "<red>You are not allowed to vanish.")
event.isCancelled = true
}
}
```
## Reporting issues
Open an issue on the [Vanish-OG Gitea repository](https://git.trueog.net/trueog/Vanish-OG/issues).
Executable
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/bash
# Fetch all submodule content.
git submodule update --force --recursive --init
+157
View File
@@ -0,0 +1,157 @@
/* ------------------------------ Plugins ------------------------------ */
plugins {
id("java") // Import Java plugin.
id("java-library") // Import Java Library plugin.
id("com.diffplug.spotless") version "8.1.0" // Import Spotless plugin.
id("com.gradleup.shadow") version "8.3.9" // Import Shadow plugin.
id("checkstyle") // Import Checkstyle plugin.
eclipse // Import Eclipse plugin.
}
/* --------------------------- JDK / Kotlin ---------------------------- */
java {
sourceCompatibility = JavaVersion.VERSION_17 // Compile with JDK 17 compatibility.
toolchain { // Select Java toolchain.
languageVersion.set(JavaLanguageVersion.of(17)) // Use JDK 17.
vendor.set(JvmVendorSpec.GRAAL_VM) // Use GraalVM CE.
}
}
/* ----------------------------- Metadata ------------------------------ */
group = "de.myzelyam.vanishog" // Declare bundle identifier.
version = "1.1" // Declare plugin version (will be in .jar).
val apiVersion = "1.13" // Declare minecraft server target version.
/* ----------------------------- Resources ----------------------------- */
tasks.named<ProcessResources>("processResources") {
val props = mapOf("version" to version, "apiVersion" to apiVersion)
inputs.properties(props) // Indicates to rerun if version changes.
filesMatching(listOf("plugin.yml", "config.yml", "messages.yml")) {
expand(props) { escapeBackslash.set(true) } // Keep literal '\n' etc. intact in YAML comments/values.
}
from("LICENSE") { into("/") } // Bundle main GPLv2 license at jar root.
from("libs/License.txt") { // Bundle ProtocolLib GPLv2 license.
into("META-INF/licenses/ProtocolLib")
rename { "LICENSE" }
}
from("libs/TAB-OG/LICENSE") { // Bundle TAB-OG license.
into("META-INF/licenses/TAB-OG")
}
}
/* ---------------------------- Repos ---------------------------------- */
repositories {
mavenCentral() // Import the Maven Central Maven Repository.
gradlePluginPortal() // Import the Gradle Plugin Portal Maven Repository.
maven { url = uri("https://repo.purpurmc.org/snapshots") } // Import the PurpurMC Maven Repository.
maven { url = uri("https://repo.papermc.io/repository/maven-public/") } // PaperMC.
maven { url = uri("https://repo.essentialsx.net/releases/") } // EssentialsX.
maven { url = uri("https://jitpack.io") } // JitPack (VaultAPI, TrailGUI, OpenInv, Dynmap).
maven { url = uri("https://repo.citizensnpcs.co/") } // Citizens.
maven { url = uri("https://libraries.minecraft.net") } // Mojang Brigadier.
}
/* ---------------------- Java project deps ---------------------------- */
dependencies {
// Purpur API (server target).
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT")
// Import TrueOG Network Utilities-OG Java API (from source).
compileOnlyApi(project(":libs:Utilities-OG"))
// EssentialsX API.
compileOnly("net.essentialsx:EssentialsX:2.21.0") {
exclude(group = "org.bstats", module = "bstats-bukkit") // Exclude bstats.
}
// LuckPerms API (group, prefix, suffix lookups).
compileOnly("net.luckperms:api:5.5") // Import the LuckPerms API.
// ProtocolLib (local jar in libs/ProtocolLib/).
compileOnly(files("libs/ProtocolLib/ProtocolLib-5.0.jar"))
// TAB-OG API (local jar in libs/TAB-OG/).
compileOnly(files("libs/TAB-OG/tab-api-4.2.0.jar"))
// Citizens API.
compileOnly("net.citizensnpcs:citizensapi:2.0.28-SNAPSHOT")
// TrailGUI (via JitPack).
compileOnly("com.github.SinnDevelopment:TrailGUI:37659dda03")
// Import MiniPlaceholders API.
compileOnly("io.github.miniplaceholders:miniplaceholders-api:2.2.3")
// Mojang Brigadier (provided at runtime by Purpur).
compileOnly("com.mojang:brigadier:1.0.18")
}
apply(from = "eclipse.gradle.kts") // Import eclipse classpath support script.
/* ---------------------- Reproducible jars ---------------------------- */
tasks.withType<AbstractArchiveTask>().configureEach { // Ensure reproducible .jars
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
/* ----------------------------- Shadow -------------------------------- */
tasks.shadowJar {
exclude("io.github.miniplaceholders.*") // Exclude the MiniPlaceholders package from being shadowed.
isEnableRelocation = true
relocationPrefix = "${project.group}.shadow"
mergeServiceFiles()
archiveClassifier.set("") // Use empty string instead of null.
archiveBaseName.set(rootProject.name) // Vanish-OG-${version}.jar
}
tasks.jar { archiveClassifier.set("part") } // Applies to root jarfile only.
tasks.build { dependsOn(tasks.spotlessApply, tasks.shadowJar) } // Build depends on spotless and shadow.
/* --------------------------- Javac opts ------------------------------- */
tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.add("-parameters") // Enable reflection for java code.
options.isFork = true // Run javac in its own process.
options.compilerArgs.add("-Xlint:deprecation") // Trigger deprecation warning messages.
options.encoding = "UTF-8" // Use UTF-8 file encoding.
}
/* ----------------------------- Auto Formatting ------------------------ */
spotless {
java {
eclipse().configFile("config/formatter/eclipse-java-formatter.xml") // Eclipse java formatting.
leadingTabsToSpaces() // Convert leftover leading tabs to spaces.
removeUnusedImports() // Remove imports that aren't being called.
}
kotlinGradle {
ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) } // JetBrains Kotlin formatting.
target("build.gradle.kts", "settings.gradle.kts") // Gradle files to format.
}
}
checkstyle {
toolVersion = "10.18.1" // Declare checkstyle version to use.
configFile = file("config/checkstyle/checkstyle.xml") // Point checkstyle to config file.
isIgnoreFailures = true // Don't fail the build if checkstyle does not pass.
isShowViolations = true // Show the violations in any IDE with the checkstyle plugin.
}
tasks.named("compileJava") {
dependsOn("spotlessApply") // Run spotless before compiling with the JDK.
}
tasks.named("spotlessCheck") {
dependsOn("spotlessApply") // Run spotless before checking if spotless ran.
}
/* ------------------------------ Eclipse SHIM ------------------------- */
// This can't be put in eclipse.gradle.kts because Gradle is weird.
subprojects {
apply(plugin = "java-library")
apply(plugin = "eclipse")
eclipse.project.name = "${project.name}-${rootProject.name}"
tasks.withType<Jar>().configureEach { archiveBaseName.set("${project.name}-${rootProject.name}") }
}
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
<property name="severity" value="error"/>
</module>
<module name="TreeWalker">
<module name="FinalLocalVariable"/>
<module name="AvoidStarImport"/>
<module name="Indentation">
<property name="severity" value="ignore"/>
</module>
</module>
<module name="RegexpSingleline">
<property name="format" value="\borg\.junit\.jupiter\.api\.Assertions\.fail\s*\(\s*&quot;Not yet implemented&quot;\s*\)\s*;"/>
<property name="message" value="Remove placeholder fail() and implement the test."/>
<property name="ignoreCase" value="true"/>
<property name="severity" value="warning"/>
</module>
<module name="RegexpSingleline">
<property name="format" value="(?&lt;!\w)fail\s*\(\s*&quot;Not yet implemented&quot;\s*\)\s*;"/>
<property name="message" value="Remove placeholder fail() and implement the test."/>
<property name="severity" value="warning"/>
</module>
</module>
+404
View File
@@ -0,0 +1,404 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="23">
<profile kind="CodeFormatterProfile" name="TrueOG Network Formatting" version="23">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case_after_arrow" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+158
View File
@@ -0,0 +1,158 @@
/* This is free and unencumbered software released into the public domain */
import org.gradle.api.tasks.bundling.Jar
import org.gradle.plugins.ide.eclipse.model.EclipseModel
import java.nio.file.Files
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
val sourcePluginProjects =
configurations
.getByName("compileClasspath")
.allDependencies
.filterIsInstance<ProjectDependency>()
.map { it.path }
.filter { it.startsWith(":libs:") }
.distinct()
val sourcePluginProjectNames = sourcePluginProjects.map { it.substringAfterLast(":") }.toSet()
sourcePluginProjects.forEach { evaluationDependsOn(it) }
val ideLibs: Configuration by
configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
}
configure<EclipseModel> {
project {
name = "${rootProject.name}-Plugin"
}
classpath {
plusConfigurations.add(ideLibs)
}
}
val ideLibDir = layout.buildDirectory.dir("ide-libs")
val hashRegex = Regex("-[0-9a-fA-F]{10}(?=\\.jar$)") // Black magic.
val copyTasks = mutableListOf<TaskProvider<Copy>>()
sourcePluginProjects.forEach { path ->
val sub = project(path)
val archiveTaskName = if ("shadowJar" in sub.tasks.names) "shadowJar" else "jar"
val archiveTask = sub.tasks.named<Jar>(archiveTaskName)
val copyTask =
tasks.register<Copy>("ideCopy${sub.name.replaceFirstChar(Char::titlecase)}") {
dependsOn(archiveTask)
from(archiveTask.flatMap { it.archiveFile })
into(ideLibDir)
rename { it.replace(hashRegex, "") } // Remove git commit hash from jarfile.
}
copyTasks += copyTask
}
/* Ensure the jars exist before .classpath is generated */
tasks.named("eclipseClasspath").configure { dependsOn(copyTasks) }
/* Supply those jars to the ideLibs configuration (after evaluation) */
afterEvaluate { dependencies { add("ideLibs", fileTree(ideLibDir) { include("*.jar") }) } }
val injectIdeLibs =
tasks.register("injectIdeLibs") {
dependsOn("eclipse") // run after all eclipse files are generated
doLast {
val cpFile = file(".classpath")
if (!cpFile.exists()) return@doLast
val jars = fileTree(ideLibDir.get()) { include("*.jar") }.files.sortedBy { it.name }
if (jars.isEmpty()) return@doLast
// Parse DOM
val dbf = DocumentBuilderFactory.newInstance()
val doc = dbf.newDocumentBuilder().parse(cpFile)
val root = doc.documentElement
// Helper to see if an entry already exists
fun exists(path: String): Boolean =
root.getElementsByTagName("classpathentry").let { list ->
(0 until list.length).any { i ->
val n = list.item(i)
val kind = n.attributes?.getNamedItem("kind")?.nodeValue
val p = n.attributes?.getNamedItem("path")?.nodeValue
kind == "lib" && p == path
}
}
// Remove any entry that points to ide-libs dir or unresolved :libs: project refs.
val toRemove = mutableListOf<org.w3c.dom.Node>()
val list = root.getElementsByTagName("classpathentry")
val dirPath = ideLibDir.get().asFile.absolutePath
for (i in 0 until list.length) {
val n = list.item(i)
val kind = n.attributes?.getNamedItem("kind")?.nodeValue
val p = n.attributes?.getNamedItem("path")?.nodeValue ?: ""
val isIdeLibEntry = kind == "lib" && (p == dirPath || p.startsWith("$dirPath/"))
val sourceProjectPath = p.removePrefix("/")
val isHalfImportedSourceModule = kind == "src" && p.startsWith("/libs:")
val isSourcePluginModule = kind == "src" && sourceProjectPath in sourcePluginProjectNames
if (isIdeLibEntry || isHalfImportedSourceModule || isSourcePluginModule) {
toRemove += n
}
}
toRemove.forEach { root.removeChild(it) }
// Append our jar entries LAST
jars.forEach { f ->
val abs = f.absolutePath
if (!exists(abs)) {
val entry = doc.createElement("classpathentry")
entry.setAttribute("kind", "lib")
entry.setAttribute("path", abs)
root.appendChild(entry)
}
}
// Write back pretty
val tf =
TransformerFactory.newInstance().newTransformer().apply {
setOutputProperty(OutputKeys.INDENT, "yes")
setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "1")
setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no")
setOutputProperty(OutputKeys.ENCODING, "UTF-8")
}
Files.newBufferedWriter(cpFile.toPath()).use { w -> tf.transform(DOMSource(doc), StreamResult(w)) }
}
}
tasks.named("eclipse").configure { finalizedBy(injectIdeLibs) }
val eclipseModel = extensions.getByType<EclipseModel>()
fun Project.addResolvableEclipseConfigs() {
val jarAttr =
objects.named(org.gradle.api.attributes.LibraryElements::class, org.gradle.api.attributes.LibraryElements.JAR)
val apiAttr = objects.named(org.gradle.api.attributes.Usage::class, org.gradle.api.attributes.Usage.JAVA_API)
val compileOnlyRes =
configurations.create("eclipseCompileOnly") {
extendsFrom(configurations.getByName("compileOnly"))
isCanBeResolved = true
isCanBeConsumed = false
attributes.attribute(org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE, apiAttr)
attributes.attribute(org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, jarAttr)
}
val compileOnlyApiRes =
configurations.create("eclipseCompileOnlyApi") {
extendsFrom(configurations.getByName("compileOnlyApi"))
isCanBeResolved = true
isCanBeConsumed = false
attributes.attribute(org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE, apiAttr)
attributes.attribute(org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, jarAttr)
}
eclipseModel.classpath.plusConfigurations.addAll(listOf(compileOnlyRes, compileOnlyApiRes))
}
addResolvableEclipseConfigs()
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+251
View File
@@ -0,0 +1,251 @@
#!/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.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# 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/HEAD/platforms/jvm/plugins-application/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
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# 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="\\\"\\\""
# 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
if ! command -v java >/dev/null 2>&1
then
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
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
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
# 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"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# 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
+94
View File
@@ -0,0 +1,94 @@
@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
@rem SPDX-License-Identifier: Apache-2.0
@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=.
@rem This is normally unused
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% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 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!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+339
View File
@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
Binary file not shown.
+174
View File
@@ -0,0 +1,174 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
Binary file not shown.
+1
Submodule libs/Utilities-OG added at 8b5c86cc9c.
-152
View File
@@ -1,152 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>de.myzelyam</groupId>
<artifactId>SuperVanish</artifactId>
<version>6.2.6</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>mvdw-software-repo</id>
<name>MVdW Public Repositories</name>
<url>http://repo.mvdw-software.be/content/groups/public/</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>essentials-repo</id>
<url>https://ci.ender.zone/plugin/repository/everything/</url>
</repository>
<repository>
<id>dmulloy2-repo</id>
<url>http://repo.dmulloy2.net/content/groups/public/</url>
</repository>
<repository>
<id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository>
<repository>
<id>citizens-repo</id>
<url>http://repo.citizensnpcs.co</url>
</repository>
<repository>
<id>placeholderapi-repo</id>
<url>http://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
</repositories>
<dependencies>
<!--Spigot API-->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.16.5-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
<!--Essentials API-->
<dependency>
<groupId>net.ess3</groupId>
<artifactId>EssentialsX</artifactId>
<version>2.17.2</version>
<scope>provided</scope>
</dependency>
<!--ProtocolLib-->
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib-API</artifactId>
<version>4.4.0-SNAPSHOT</version>
</dependency>
<!--Vault API-->
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<!--Citizens API-->
<dependency>
<groupId>net.citizensnpcs</groupId>
<artifactId>citizensapi</artifactId>
<version>2.0.25-SNAPSHOT</version>
<type>jar</type>
</dependency>
<!--TrailGUI-->
<dependency>
<groupId>ca.jamiesinn.trailgui</groupId>
<artifactId>TrailGUI</artifactId>
<scope>system</scope>
<systemPath>${basedir}/dependencies/TrailGUI-5.15-SNAPSHOT.jar</systemPath>
<version>1.0</version>
</dependency>
<!--Dynmap-->
<dependency>
<groupId>org.dynmap</groupId>
<artifactId>Dynmap</artifactId>
<scope>system</scope>
<systemPath>${basedir}/dependencies/Dynmap-3.0-beta-4-spigot.jar</systemPath>
<version>1.0</version>
</dependency>
<!--SuperTrails-->
<dependency>
<groupId>me.kvq.plugin.trails</groupId>
<artifactId>SuperTrails</artifactId>
<scope>system</scope>
<systemPath>${basedir}/dependencies/SuperTrails.jar</systemPath>
<version>1.0</version>
</dependency>
<!--MVdWPlaceholderAPI-->
<dependency>
<groupId>be.maximvdw</groupId>
<artifactId>MVdWPlaceholderAPI</artifactId>
<version>3.1.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--PlaceholderAPI-->
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.10.6</version>
</dependency>
</dependencies>
</project>
+13
View File
@@ -0,0 +1,13 @@
rootProject.name = "Vanish-OG"
ProcessBuilder("sh", "bootstrap.sh").directory(rootDir).inheritIO().start().let {
if (it.waitFor() != 0) throw GradleException("bootstrap.sh failed")
}
file("libs")
.listFiles()
?.filter { it.isDirectory && !it.name.startsWith(".") }
?.forEach { dir ->
include(":libs:${dir.name}")
project(":libs:${dir.name}").projectDir = dir
}
@@ -20,34 +20,49 @@ public class PlayerHideEvent extends PlayerEvent implements Cancellable {
private boolean isCancelled = false;
public PlayerHideEvent(Player p, boolean silent) {
super(p);
this.silent = silent;
}
public static HandlerList getHandlerList() {
return handlers;
}
public boolean isSilent() {
return silent;
}
public void setSilent(boolean silent) {
this.silent = silent;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean cancel) {
isCancelled = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}
@@ -20,34 +20,49 @@ public class PlayerShowEvent extends PlayerEvent implements Cancellable {
private boolean isCancelled = false;
public PlayerShowEvent(Player p, boolean silent) {
super(p);
this.silent = silent;
}
public static HandlerList getHandlerList() {
return handlers;
}
public boolean isSilent() {
return silent;
}
public void setSilent(boolean silent) {
this.silent = silent;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean cancel) {
isCancelled = cancel;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}
@@ -8,6 +8,8 @@
package de.myzelyam.api.vanish;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
@@ -25,19 +27,31 @@ public class PlayerVanishStateChangeEvent extends Event implements Cancellable {
private boolean isCancelled = false;
public PlayerVanishStateChangeEvent(UUID uuid, String name, boolean vanishing, String cause) {
this.vanishing = vanishing;
this.uuid = uuid;
this.name = name;
this.cause = cause;
}
public PlayerVanishStateChangeEvent(Player player, boolean vanishing, String cause) {
this(player.getUniqueId(), player.getName(), vanishing, cause);
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
/**
@@ -45,41 +59,65 @@ public class PlayerVanishStateChangeEvent extends Event implements Cancellable {
*/
@Override
public void setCancelled(boolean cancel) {
isCancelled = cancel;
}
/**
* @return TRUE if the player is vanishing, FALSE if the player is reappearing
*/
public boolean isVanishing() {
return vanishing;
}
/**
* @return The name of the player who is vanishing/reappearing
*/
public String getName() {
return name;
}
/**
* @return The UUID of the player who is vanishing/reappearing
*/
public UUID getUUID() {
return uuid;
}
/**
* @return The name of the command sender who caused the vanish state change or null if the cause is
* either not specified or it's SuperVanish itself, please note that if this returns 'CONSOLE' then it's
* the console which caused this state change
* @return The Bukkit Player who is vanishing/reappearing, or null if the player
* is not currently online
*/
public Player getPlayer() {
return Bukkit.getPlayer(uuid);
}
/**
* @return The name of the command sender who caused the vanish state change or
* null if the cause is either not specified or it's SuperVanish itself,
* please note that if this returns 'CONSOLE' then it's the console
* which caused this state change
*/
public String getCause() {
return cause;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}
@@ -18,20 +18,29 @@ public class PostPlayerHideEvent extends PlayerEvent {
private final boolean silent;
public PostPlayerHideEvent(Player p, boolean silent) {
super(p);
this.silent = silent;
}
public static HandlerList getHandlerList() {
return handlers;
}
public boolean isSilent() {
return silent;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}
@@ -18,20 +18,29 @@ public class PostPlayerShowEvent extends PlayerEvent {
private final boolean silent;
public PostPlayerShowEvent(Player p, boolean silent) {
super(p);
this.silent = silent;
}
public static HandlerList getHandlerList() {
return handlers;
}
public boolean isSilent() {
return silent;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}
@@ -30,38 +30,45 @@ public class VanishAPI {
* @return A collection of the UUIDs of all online vanished players
*/
public static List<UUID> getInvisiblePlayers() {
return new ArrayList<>(PLUGIN.getVanishStateMgr().getOnlineVanishedPlayers());
}
/**
* @return A collection of the UUIDs of all vanished players, both online and offline players
* @return A collection of the UUIDs of all vanished players, both online and
* offline players
*/
public static List<UUID> getAllInvisiblePlayers() {
return new ArrayList<>(PLUGIN.getVanishStateMgr().getVanishedPlayers());
}
/**
* Player must be online for this to return true if MySQL is enabled
*
* @param p - the player.
* @return TRUE if the player is invisible, FALSE otherwise.
*/
public static boolean isInvisible(Player p) {
Validation.checkNotNull("Player cannot be null!", p);
return PLUGIN.getVanishStateMgr().isVanished(p.getUniqueId());
}
/**
* Checks if a player is invisible, online or not
* <p/>
* Deprecated: Will cause minor lag if mysql is enabled, use asynchronously or sparingly
* Checks if a player is vanished.
*
* @param uuid - the player's UUID.
* @return TRUE if the player is invisible, FALSE otherwise.
* @return TRUE if the player is vanished, FALSE otherwise.
*/
public static boolean isInvisibleOffline(UUID uuid) {
public static boolean isVanished(UUID uuid) {
Validation.checkNotNull("UUID cannot be null!", uuid);
return PLUGIN.getVanishStateMgr().isVanished(uuid);
}
/**
* Checks if a player is vanished.
*
* @param player - the player.
* @return TRUE if the player is vanished, FALSE otherwise.
*/
public static boolean isVanished(Player player) {
Validation.checkNotNull("Player cannot be null!", player);
return PLUGIN.getVanishStateMgr().isVanished(player);
}
/**
@@ -70,8 +77,10 @@ public class VanishAPI {
* @param p - the player.
*/
public static void hidePlayer(Player p) {
Validation.checkNotNull("Player cannot be null!", p);
PLUGIN.getVisibilityChanger().hidePlayer(p);
}
/**
@@ -80,8 +89,10 @@ public class VanishAPI {
* @param p - the player.
*/
public static void showPlayer(Player p) {
Validation.checkNotNull("Player cannot be null!", p);
PLUGIN.getVisibilityChanger().showPlayer(p);
}
/**
@@ -89,33 +100,43 @@ public class VanishAPI {
*
* @param viewer - the viewer
* @param viewed - the viewed player
* @return TRUE if viewed is not vanished or viewer has the permission to see viewed
* @return TRUE if viewed is not vanished or viewer has the permission to see
* viewed
*/
public static boolean canSee(Player viewer, Player viewed) {
return PLUGIN.canSee(viewer, viewed);
}
public static FileConfiguration getConfiguration() {
return PLUGIN.getSettings();
}
public static FileConfiguration getMessages() {
return PLUGIN.getMessages();
}
public static FileConfiguration getPlayerData() {
return PLUGIN.getPlayerData();
return PLUGIN.getMessages();
}
public static void reloadConfig() {
PLUGIN.reload();
}
public static SuperVanish getPlugin() {
return PLUGIN;
}
public static void setPlugin(SuperVanish plugin) {
VanishAPI.PLUGIN = plugin;
}
}
}
@@ -18,48 +18,64 @@ public class LayeredPermissionChecker {
private final FileConfiguration settings;
public LayeredPermissionChecker(SuperVanish plugin) {
this.plugin = plugin;
settings = plugin.getSettings();
}
/**
* @return TRUE if sender has *permission* to use /sv on, else FALSE; TRUE doesn't mean that sender can
* actually use /sv on
* @return TRUE if sender has *permission* to use /sv on, else FALSE; TRUE
* doesn't mean that sender can actually use /sv on
*/
public boolean hasPermissionToVanish(CommandSender sender) {
if (settings.getBoolean(
"IndicationFeatures.LayeredPermissions.LayeredSeeAndUsePermissions", false)) {
if (sender.hasPermission("sv.use")) return true;
if (settings.getBoolean("IndicationFeatures.LayeredPermissions.LayeredSeeAndUsePermissions", false)) {
if (sender.hasPermission("sv.use"))
return true;
int permissionLevel;
if (sender instanceof Player)
permissionLevel = plugin.getVanishPlayer((Player) sender).getUsePermissionLevel();
else permissionLevel = getLayeredPermissionLevel(sender, "use");
else
permissionLevel = getLayeredPermissionLevel(sender, "use");
return permissionLevel > 0 && sender.hasPermission("sv.use.level" + permissionLevel);
} else return sender.hasPermission("sv.use");
} else
return sender.hasPermission("sv.use");
}
public boolean hasPermissionToSee(Player viewer, Player viewed) {
if (viewer == null)
throw new IllegalArgumentException("viewer cannot be null");
if (viewer == viewed) return true;
if (settings.getBoolean(
"IndicationFeatures.LayeredPermissions.LayeredSeeAndUsePermissions", false)) {
if (viewer == viewed)
return true;
if (settings.getBoolean("IndicationFeatures.LayeredPermissions.LayeredSeeAndUsePermissions", false)) {
VanishPlayer vanishViewer = plugin.getVanishPlayer(viewer);
VanishPlayer vanishViewed = plugin.getVanishPlayer(viewed);
int viewerLevel = vanishViewer.getSeePermissionLevel();
if (viewerLevel == 0) return false;
if (viewerLevel == 0)
return false;
int viewedLevel = Math.max(1, vanishViewed.getUsePermissionLevel());
return viewerLevel >= viewedLevel;
} else {
boolean enableSeePermission = settings
.getBoolean("IndicationFeatures.LayeredPermissions.EnableSeePermission", true);
return enableSeePermission && viewer.hasPermission("sv.see");
}
}
public int getLayeredPermissionLevel(CommandSender sender, String permission) {
boolean enableSeePermission = settings
.getBoolean("IndicationFeatures.LayeredPermissions.EnableSeePermission", true);
boolean enableSeePermission = settings.getBoolean("IndicationFeatures.LayeredPermissions.EnableSeePermission",
true);
if (!enableSeePermission && permission.equalsIgnoreCase("see"))
return 0;
int maxLevel = settings.getInt("IndicationFeatures.LayeredPermissions.MaxLevel", 100);
@@ -68,5 +84,7 @@ public class LayeredPermissionChecker {
if (sender.hasPermission("sv." + permission + ".level" + i))
level = i;
return level;
}
}
@@ -8,169 +8,297 @@
package de.myzelyam.supervanish;
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;
import de.myzelyam.supervanish.hooks.PlaceholderAPIHook;
import de.myzelyam.supervanish.utils.Validation;
import net.milkbowl.vault.chat.Chat;
import net.milkbowl.vault.permission.Permission;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;
import be.maximvdw.placeholderapi.PlaceholderAPI;
import de.myzelyam.supervanish.utils.Validation;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.cacheddata.CachedMetaData;
import net.trueog.utilitiesog.UtilitiesOG;
public class PlaceholderConverter {
private final SuperVanish plugin;
private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection();
public PlaceholderConverter(SuperVanish plugin) {
this.plugin = plugin;
}
public String replacePlaceholders(String msg, Object... additionalPlayerInfo) {
Validation.checkIsTrue("Failed to replace variables (Illegal arguments)",
msg != null, additionalPlayerInfo != null);
//noinspection ConstantConditions
Validation.checkIsTrue(additionalPlayerInfo.length > 0);
// check vararg
final List<Object> additionalPlayerInfoList = Arrays
.asList(additionalPlayerInfo);
Object unspecifiedPlayer = additionalPlayerInfoList.get(0);
String unspecifiedOtherPlayersName = null;
if (additionalPlayerInfoList.size() > 1
&& (additionalPlayerInfoList.get(1) instanceof String
|| additionalPlayerInfoList.get(1) instanceof Player)) {
unspecifiedOtherPlayersName = (String) (additionalPlayerInfoList
.get(1) instanceof Player
? ((Player) additionalPlayerInfoList.get(1)).getName()
: additionalPlayerInfoList.get(1));
}
//noinspection ConstantConditions
msg = msg.replace("\\n", "\n");
// replace sender specific variables
replaceVariables:
{
if (unspecifiedPlayer instanceof OfflinePlayer
&& !(unspecifiedPlayer instanceof Player)) {
// offline player
OfflinePlayer specifiedPlayer = (OfflinePlayer) unspecifiedPlayer;
// MVdWPlaceholderAPI
if (Bukkit.getPluginManager().isPluginEnabled("MVdWPlaceholderAPI")
&& plugin.getSettings().getBoolean("HookOptions.EnableMVdWPlaceholderAPIHook", true)) {
String replaced = PlaceholderAPI.replacePlaceholders(specifiedPlayer, msg);
msg = replaced == null ? msg : replaced;
}
// replace essentials nick names
if (Bukkit.getPluginManager()
.getPlugin("Essentials") != null) {
msg = msg.replace("%nick%", specifiedPlayer.getName());
}
// replace general variables
msg = msg.replace("%d%", specifiedPlayer.getName())
.replace("%p%", specifiedPlayer.getName())
.replace("%tab%", specifiedPlayer.getName());
// replace other player's name if possible
msg = msg.replace("%other%", unspecifiedOtherPlayersName != null
? unspecifiedOtherPlayersName : "UNKNOWN");
break replaceVariables;
}
if (unspecifiedPlayer instanceof Player) {
// player
Player specifiedPlayer = (Player) unspecifiedPlayer;
// PlaceholderAPI
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")
&& plugin.getSettings().getBoolean("HookOptions.EnablePlaceholderAPIHook", true)) {
String replaced = PlaceholderAPIHook.translatePlaceholders(msg, specifiedPlayer);
//noinspection ConstantConditions
msg = replaced == null ? msg : replaced;
}
// MVdWPlaceholderAPI
if (Bukkit.getPluginManager().isPluginEnabled("MVdWPlaceholderAPI")
&& plugin.getSettings().getBoolean("HookOptions.EnableMVdWPlaceholderAPIHook", true)) {
String replaced = PlaceholderAPI.replacePlaceholders(specifiedPlayer, msg);
msg = replaced == null ? msg : replaced;
}
// replace essentials nick names
if (Bukkit.getPluginManager().getPlugin("Essentials") != null) {
Essentials ess = (Essentials) Bukkit.getServer()
.getPluginManager().getPlugin("Essentials");
User u = ess.getUser(specifiedPlayer);
if (u != null)
if (u.getNickname() != null)
msg = msg.replace("%nick%", u.getNickname());
}
// replace vault info
if (Bukkit.getPluginManager().getPlugin("Vault") != null) {
RegisteredServiceProvider<Permission> permService = plugin.getServer()
.getServicesManager().getRegistration(Permission.class);
RegisteredServiceProvider<Chat> chatService = plugin.getServer()
.getServicesManager().getRegistration(Chat.class);
Permission permAPI = permService != null ? permService.getProvider() : null;
Chat chatAPI = chatService != null ? chatService.getProvider() : null;
try {
if (permAPI != null) {
String group = permAPI.getPrimaryGroup(specifiedPlayer);
if (group != null)
msg = msg.replace("%group%", group);
}
if (chatAPI != null) {
String prefix = chatAPI.getPlayerPrefix(specifiedPlayer);
String suffix = chatAPI.getPlayerSuffix(specifiedPlayer);
if (prefix != null) {
msg = msg.replace("%prefix%", prefix);
}
if (suffix != null) {
msg = msg.replace("%suffix%", suffix);
}
}
} catch (UnsupportedOperationException ignored) {
}
}
// replace general variables
msg = msg.replace("%d%", "" + specifiedPlayer.getDisplayName())
.replace("%p%", "" + specifiedPlayer.getName())
.replace("%tab%",
"" + specifiedPlayer.getPlayerListName());
// replace other player's name if possible
msg = msg.replace("%other%", unspecifiedOtherPlayersName != null
? unspecifiedOtherPlayersName : "UNKNOWN");
break replaceVariables;
}
if (unspecifiedPlayer instanceof CommandSender) {
// console
// replace general variables
msg = msg.replace("%d%", "Console").replace("%p%", "Console")
.replace("%tab%", "Console");
// replace other player's name if possible
msg = msg.replace("%other%", unspecifiedOtherPlayersName != null
? unspecifiedOtherPlayersName : "UNKNOWN");
}
}
// convert color codes
if (plugin.getVersionUtil().isOneDotXOrHigher(16)) {
Pattern pattern = Pattern.compile("#[a-fA-F0-9]{6}");
Matcher matcher = pattern.matcher(msg);
return LEGACY_SERIALIZER.serialize(expandPlaceholders(msg, additionalPlayerInfo));
while (matcher.find()) {
String color = msg.substring(matcher.start(), matcher.end());
msg = msg.replace(color, net.md_5.bungee.api.ChatColor.of(color) + "");
matcher = pattern.matcher(msg);
}
}
msg = ChatColor.translateAlternateColorCodes('&', msg);
return msg;
}
public Component expandPlaceholders(String msg, Object... additionalPlayerInfo) {
return expandPlaceholders(null, msg, additionalPlayerInfo);
}
public Component expandPlaceholders(CommandSender recipient, String msg, Object... additionalPlayerInfo) {
Validation.checkNotNull("Failed to replace variables (Illegal arguments)", msg, additionalPlayerInfo);
final PlaceholderContext context = parseContext(additionalPlayerInfo);
final String preparedMessage = applyInlinePlaceholders(msg.replace("\\n", "\n"), context);
if (recipient instanceof Player player) {
if (context.primaryPlayer != null) {
return UtilitiesOG.trueogExpand(preparedMessage, player, context.primaryPlayer);
}
return UtilitiesOG.trueogExpand(preparedMessage, player);
}
if (context.primaryPlayer != null) {
return UtilitiesOG.trueogExpand(preparedMessage, context.primaryPlayer);
}
return UtilitiesOG.trueogExpand(preparedMessage);
}
public static MessagePlaceholder placeholder(String name, Object value) {
return new MessagePlaceholder(name, value == null ? "" : String.valueOf(value));
}
private PlaceholderContext parseContext(Object... additionalPlayerInfo) {
final PlaceholderContext context = new PlaceholderContext();
if (additionalPlayerInfo == null) {
return context;
}
for (Object entry : additionalPlayerInfo) {
if (entry instanceof MessagePlaceholder messagePlaceholder) {
context.inlinePlaceholders.add(messagePlaceholder);
continue;
}
if (context.primaryObject == null) {
context.primaryObject = entry;
if (entry instanceof Player player) {
context.primaryPlayer = player;
}
continue;
}
if (context.otherName == null && (entry instanceof Player || entry instanceof String)) {
if (entry instanceof Player player) {
context.otherName = player.getName();
} else {
context.otherName = String.valueOf(entry);
}
}
}
return context;
}
private String applyInlinePlaceholders(String message, PlaceholderContext context) {
message = replaceTag(message, "sv_player_name", getPrimaryName(context.primaryObject));
message = replaceTag(message, "sv_player_display_name", getPrimaryDisplayName(context.primaryObject));
message = replaceTag(message, "sv_player_tab_name", getPrimaryTabName(context.primaryObject));
message = replaceTag(message, "sv_player_prefix", getPrimaryPrefix(context.primaryObject));
message = replaceTag(message, "sv_player_suffix", getPrimarySuffix(context.primaryObject));
message = replaceTag(message, "sv_player_group", getPrimaryGroup(context.primaryObject));
message = replaceTag(message, "sv_player_nick", getPrimaryNick(context.primaryObject));
message = replaceTag(message, "sv_other_name", context.otherName != null ? context.otherName : "UNKNOWN");
for (MessagePlaceholder inlinePlaceholder : context.inlinePlaceholders) {
message = replaceTag(message, inlinePlaceholder.name(), inlinePlaceholder.value());
}
return message;
}
private String getPrimaryName(Object primaryObject) {
if (primaryObject instanceof OfflinePlayer offlinePlayer) {
return offlinePlayer.getName();
}
if (primaryObject instanceof CommandSender) {
return "Console";
}
return "";
}
private String getPrimaryDisplayName(Object primaryObject) {
if (primaryObject instanceof Player player) {
return LEGACY_SERIALIZER.serialize(player.displayName());
}
return getPrimaryName(primaryObject);
}
private String getPrimaryTabName(Object primaryObject) {
if (primaryObject instanceof Player player) {
return LEGACY_SERIALIZER.serialize(player.playerListName());
}
return getPrimaryName(primaryObject);
}
private String getPrimaryNick(Object primaryObject) {
if (!(primaryObject instanceof Player player) || Bukkit.getPluginManager().getPlugin("Essentials") == null) {
return getPrimaryName(primaryObject);
}
final Essentials essentials = (Essentials) Bukkit.getServer().getPluginManager().getPlugin("Essentials");
final User user = essentials.getUser(player);
if (user == null || user.getNickname() == null) {
return player.getName();
}
return user.getNickname();
}
private String getPrimaryGroup(Object primaryObject) {
if (!(primaryObject instanceof OfflinePlayer offlinePlayer)) {
return "";
}
if (Bukkit.getPluginManager().getPlugin("LuckPerms") == null) {
return "";
}
try {
final LuckPerms luckPerms = LuckPermsProvider.get();
final net.luckperms.api.model.user.User user = luckPerms.getUserManager()
.getUser(offlinePlayer.getUniqueId());
return user == null ? "" : user.getPrimaryGroup();
} catch (IllegalStateException ignored) {
return "";
}
}
private String getPrimaryPrefix(Object primaryObject) {
final CachedMetaData metaData = getPrimaryMetaData(primaryObject);
return metaData == null || metaData.getPrefix() == null ? "" : metaData.getPrefix();
}
private String getPrimarySuffix(Object primaryObject) {
final CachedMetaData metaData = getPrimaryMetaData(primaryObject);
return metaData == null || metaData.getSuffix() == null ? "" : metaData.getSuffix();
}
private CachedMetaData getPrimaryMetaData(Object primaryObject) {
if (!(primaryObject instanceof OfflinePlayer offlinePlayer)
|| Bukkit.getPluginManager().getPlugin("LuckPerms") == null)
{
return null;
}
try {
final LuckPerms luckPerms = LuckPermsProvider.get();
final net.luckperms.api.model.user.User user = luckPerms.getUserManager()
.getUser(offlinePlayer.getUniqueId());
return user == null ? null : user.getCachedData().getMetaData();
} catch (IllegalStateException ignored) {
return null;
}
}
private String replaceTag(String message, String tagName, String value) {
return message.replace("<" + tagName + ">", value == null ? "" : value);
}
public record MessagePlaceholder(String name, String value) {
}
private static final class PlaceholderContext {
private Object primaryObject;
private Player primaryPlayer;
private String otherName;
private final List<MessagePlaceholder> inlinePlaceholders = new ArrayList<>();
}
}
@@ -8,22 +8,13 @@
package de.myzelyam.supervanish;
import com.comphenix.protocol.ProtocolLibrary;
import de.myzelyam.api.vanish.VanishAPI;
import de.myzelyam.supervanish.commands.VanishCommand;
import de.myzelyam.supervanish.config.ConfigMgr;
import de.myzelyam.supervanish.listeners.*;
import de.myzelyam.supervanish.features.FeatureMgr;
import de.myzelyam.supervanish.hooks.PluginHookMgr;
import de.myzelyam.supervanish.net.UpdateNotifier;
import de.myzelyam.supervanish.utils.ExceptionLogger;
import de.myzelyam.supervanish.utils.VersionUtil;
import de.myzelyam.supervanish.visibility.ActionBarMgr;
import de.myzelyam.supervanish.visibility.FileVanishStateMgr;
import de.myzelyam.supervanish.visibility.ServerListPacketListener;
import de.myzelyam.supervanish.visibility.VisibilityChanger;
import de.myzelyam.supervanish.visibility.hiders.PreventionHider;
import lombok.Getter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@@ -34,261 +25,610 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import com.comphenix.protocol.ProtocolLibrary;
import de.myzelyam.api.vanish.VanishAPI;
import de.myzelyam.supervanish.commands.VanishCommand;
import de.myzelyam.supervanish.config.ConfigMgr;
import de.myzelyam.supervanish.features.FeatureMgr;
import de.myzelyam.supervanish.hooks.PluginHookMgr;
import de.myzelyam.supervanish.listeners.GeneralListener;
import de.myzelyam.supervanish.listeners.JoinListener;
import de.myzelyam.supervanish.listeners.LoginListener;
import de.myzelyam.supervanish.listeners.PlayerBlockModifyListener;
import de.myzelyam.supervanish.listeners.QuitListener;
import de.myzelyam.supervanish.listeners.TabCompleteListener;
import de.myzelyam.supervanish.listeners.WorldChangeListener;
import de.myzelyam.supervanish.utils.ExceptionLogger;
import de.myzelyam.supervanish.utils.BukkitPlayerHidingUtil;
import de.myzelyam.supervanish.utils.VersionUtil;
import de.myzelyam.supervanish.visibility.ActionBarMgr;
import de.myzelyam.supervanish.visibility.ServerListPacketListener;
import de.myzelyam.supervanish.visibility.VanishStateMgr;
import de.myzelyam.supervanish.visibility.VisibilityChanger;
import de.myzelyam.supervanish.visibility.YamlVanishStateRepository;
import de.myzelyam.supervanish.visibility.hiders.PreventionHider;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.trueog.utilitiesog.UtilitiesOG;
public class SuperVanish extends JavaPlugin implements SuperVanishPlugin {
public static final String[] NON_REQUIRED_SETTINGS_UPDATES = {"6.0.0", "6.0.1", "6.0.2", "6.0.3",
"6.0.4", "6.0.5", "6.1.0", "6.1.1", "6.1.2", "6.1.3", "6.1.4", "6.1.5", "6.1.6", "6.1.7",
"6.1.8", "6.2.0", "6.2.1", "6.2.2", "6.2.3", "6.2.4", "6.2.5"},
NON_REQUIRED_MESSAGES_UPDATES = {"6.0.0", "6.0.1", "6.0.2", "6.0.3", "6.0.4", "6.0.5", "6.1.0",
"6.1.1", "6.1.2", "6.1.3", "6.1.4", "6.1.5", "6.1.6", "6.1.7", "6.1.8", "6.2.0", "6.2.1",
"6.2.2", "6.2.3", "6.2.4", "6.2.5"};
public static final String[] NON_REQUIRED_MESSAGES_UPDATES = { "6.0.0", "6.0.1", "6.0.2", "6.0.3", "6.0.4", "6.0.5",
"6.1.0", "6.1.1", "6.1.2", "6.1.3", "6.1.4", "6.1.5", "6.1.6", "6.1.7", "6.1.8", "6.2.0", "6.2.1", "6.2.2",
"6.2.3", "6.2.4", "6.2.5", "6.2.6", "6.2.7", "6.2.8", "6.2.9", "6.2.10", "6.2.11", "6.2.12", "6.2.13",
"6.2.14", "6.2.15", "6.2.16", "6.2.17", "6.2.18", "6.2.19", "6.2.20" };
@Getter
private boolean useProtocolLib;
@Getter
private ActionBarMgr actionBarMgr;
@Getter
private FileVanishStateMgr vanishStateMgr;
@Getter
private VanishStateMgr vanishStateMgr;
private VersionUtil versionUtil;
@Getter
private ConfigMgr configMgr;
@Getter
private FeatureMgr featureMgr;
@Getter
private PlaceholderConverter placeholderConverter;
@Getter
private VanishCommand command;
@Getter
private VisibilityChanger visibilityChanger;
@Getter
private UpdateNotifier updateNotifier;
@Getter
private LoginListener loginListener;
@Getter
private LayeredPermissionChecker layeredPermissionChecker;
private Set<VanishPlayer> vanishPlayers = new HashSet<>();
private PluginHookMgr pluginHookMgr;
private final Set<VanishPlayer> vanishPlayers = new HashSet<>();
@Override
public void onEnable() {
try {
useProtocolLib = getServer().getPluginManager().isPluginEnabled("ProtocolLib");
if (!useProtocolLib) log(Level.INFO,
"Please install ProtocolLib to be able to use all SuperVanish features: " +
"https://www.spigotmc.org/resources/protocollib.1997/");
if (!useProtocolLib) {
log(Level.INFO, "Please install ProtocolLib to be able to use all Vanish-OG features: "
+ "https://www.spigotmc.org/resources/protocollib.1997/");
}
configMgr = new ConfigMgr(this);
configMgr.prepareFiles();
placeholderConverter = new PlaceholderConverter(this);
layeredPermissionChecker = new LayeredPermissionChecker(this);
command = new VanishCommand(this);
versionUtil = new VersionUtil(this);
vanishStateMgr = new FileVanishStateMgr(this);
if (getSettings().getBoolean("MiscellaneousOptions.UpdateChecker.Enable", true))
updateNotifier = new UpdateNotifier(this);
vanishStateMgr = new VanishStateMgr(this, new YamlVanishStateRepository(this));
configMgr.checkFilesForLeftOvers();
visibilityChanger = new VisibilityChanger(new PreventionHider(this), this);
if (versionUtil.isOneDotXOrHigher(8) && useProtocolLib)
if (versionUtil.isOneDotXOrHigher(8) && useProtocolLib) {
actionBarMgr = new ActionBarMgr(this);
if (useProtocolLib && ServerListPacketListener.isEnabled(this))
}
if (useProtocolLib && ServerListPacketListener.isEnabled(this)) {
ServerListPacketListener.register(this);
}
registerEvents();
new PluginHookMgr(this);
pluginHookMgr = new PluginHookMgr(this);
featureMgr = new FeatureMgr(this);
featureMgr.enableFeatures();
if (!Bukkit.getOnlinePlayers().isEmpty())
if (!Bukkit.getOnlinePlayers().isEmpty()) {
onReload();
}
} catch (Exception e) {
logException(e);
}
try {
VanishAPI.setPlugin(this);
} catch (NoSuchMethodError ignored) {
// API already loaded by other plugin
}
}
@Override
public void onDisable() {
try {
if (featureMgr != null) featureMgr.disableFeatures();
// Unhook from TAB-OG before tearing down VanishStateMgr so no stale
// handler survives across reload with a disabled plugin reference.
if (pluginHookMgr != null) {
pluginHookMgr.onSuperVanishDisable();
}
forceShowAllPlayers();
if (visibilityChanger != null) {
visibilityChanger.getHider().clearHiddenState();
}
if (featureMgr != null) {
featureMgr.disableFeatures();
}
if (vanishStateMgr != null) {
vanishStateMgr.close();
}
vanishPlayers.clear();
VanishAPI.setPlugin(null);
} catch (Throwable e) {
if (e instanceof ThreadDeath || e instanceof VirtualMachineError) throw e;
if (!(e instanceof NoClassDefFoundError | e instanceof NoSuchMethodError)) {
e.printStackTrace();
if (e instanceof ThreadDeath || e instanceof VirtualMachineError) {
throw e;
}
if (!(e instanceof NoClassDefFoundError | e instanceof NoSuchMethodError)) {
e.printStackTrace();
}
}
}
private void onReload() {
for (Player player : Bukkit.getOnlinePlayers()) {
boolean itemPickUps = getPlayerData().getBoolean(
"PlayerData." + player.getUniqueId() + ".itemPickUps",
forceShowAllPlayers();
visibilityChanger.getHider().clearHiddenState();
Bukkit.getOnlinePlayers().forEach((Player player) -> {
final boolean itemPickUps = vanishStateMgr.getItemPickUps(player.getUniqueId(),
getSettings().getBoolean("InvisibilityFeatures.DefaultPickUpItemsOption"));
boolean vanished = vanishStateMgr.isVanished(player.getUniqueId());
final boolean vanished = vanishStateMgr.isVanished(player.getUniqueId());
createVanishPlayer(player, itemPickUps);
if (vanished) {
for (Player onlinePlayer : Bukkit.getOnlinePlayers())
if (!hasPermissionToSee(onlinePlayer, player))
visibilityChanger.getHider().setHidden(player, onlinePlayer, true);
}
if (getSettings().getBoolean("MessageOptions.DisplayActionBar")
&& vanished && actionBarMgr != null) {
if (vanished)
player.setMetadata("vanished", new FixedMetadataValue(this, true));
else
player.removeMetadata("vanished", this);
if (getSettings().getBoolean("MessageOptions.DisplayActionBar") && vanished && actionBarMgr != null) {
actionBarMgr.addActionBar(player);
}
}
});
reconcileAllVisibilities();
}
public void reload() {
getServer().getScheduler().cancelTasks(this);
HandlerList.unregisterAll(this);
if (useProtocolLib)
if (useProtocolLib) {
ProtocolLibrary.getProtocolManager().removePacketListeners(this);
}
onDisable();
onEnable();
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
return this.command.tabComplete(command, sender, alias, args);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
this.command.execute(command, sender, label, args);
return true;
}
private void registerEvents() {
PluginManager pluginManager = getServer().getPluginManager();
final PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new GeneralListener(this), this);
pluginManager.registerEvents(new PlayerBlockModifyListener(this), this);
pluginManager.registerEvents(new WorldChangeListener(this), this);
if (versionUtil.isOneDotXOrHigher(10)) {
pluginManager.registerEvents(new TabCompleteListener(this), this);
}
pluginManager.registerEvents(loginListener = new LoginListener(this), this);
JoinListener joinListener = new JoinListener(this);
pluginManager.registerEvent(PlayerJoinEvent.class, joinListener,
getEventPriority(PlayerJoinEvent.class), joinListener, this, false);
QuitListener quitListener = new QuitListener(this);
pluginManager.registerEvent(PlayerQuitEvent.class, quitListener,
getEventPriority(PlayerQuitEvent.class), quitListener, this, false);
final JoinListener joinListener = new JoinListener(this);
pluginManager.registerEvent(PlayerJoinEvent.class, joinListener, getEventPriority(PlayerJoinEvent.class),
joinListener, this, false);
final QuitListener quitListener = new QuitListener(this);
pluginManager.registerEvent(PlayerQuitEvent.class, quitListener, getEventPriority(PlayerQuitEvent.class),
quitListener, this, false);
}
private EventPriority getEventPriority(Class<? extends Event> eventClass) {
try {
String eventName = eventClass.getSimpleName();
String configString = getSettings().getString("CompatibilityOptions." + eventName + "Priority");
if (configString == null) return EventPriority.NORMAL;
EventPriority priority = EventPriority.valueOf(configString);
return priority;
final String eventName = eventClass.getSimpleName();
final String configString = getSettings().getString("CompatibilityOptions." + eventName + "Priority");
if (configString == null) {
return EventPriority.NORMAL;
}
return EventPriority.valueOf(configString);
} catch (Exception e) {
logException(e);
return EventPriority.NORMAL;
}
}
public String replacePlaceholders(String msg, Object... additionalPlayerInfo) {
return placeholderConverter.replacePlaceholders(msg, additionalPlayerInfo);
}
public Component expandPlaceholders(CommandSender recipient, String msg, Object... additionalPlayerInfo) {
return placeholderConverter.expandPlaceholders(recipient, msg, additionalPlayerInfo);
}
public String getMessage(String path) {
String message = getMessages().getString("Messages." + path);
if (message == null) {
message = configMgr.getMessagesFile().getDefaultConfig().getString("Messages." + path);
}
return message;
}
public VanishPlayer getVanishPlayer(Player player) {
for (VanishPlayer vanishPlayer : vanishPlayers) {
if (vanishPlayer.getPlayer().equals(player)) {
if (vanishPlayer.getPlayerUUID().equals(player.getUniqueId())) {
return vanishPlayer;
}
}
// ensure that there is always a vanish player
boolean itemPickUps = getPlayerData().getBoolean(
"PlayerData." + player.getUniqueId() + ".itemPickUps",
final boolean itemPickUps = vanishStateMgr.getItemPickUps(player.getUniqueId(),
getSettings().getBoolean("InvisibilityFeatures.DefaultPickUpItemsOption"));
final VanishPlayer vanishPlayer = new VanishPlayer(player, this, itemPickUps);
vanishPlayers.add(vanishPlayer);
return vanishPlayer;
}
public void createVanishPlayer(Player player, boolean itemPickUps) {
VanishPlayer vanishPlayer = new VanishPlayer(player, this, itemPickUps);
final VanishPlayer vanishPlayer = new VanishPlayer(player, this, itemPickUps);
vanishPlayers.add(vanishPlayer);
}
public void removeVanishPlayer(VanishPlayer vanishPlayer) {
vanishPlayers.remove(vanishPlayer);
}
public void sendMessage(CommandSender p, String messagesYmlPath, Object... additionalPlayerInfo) {
String message;
if (!messagesYmlPath.contains(" "))
if (!StringUtils.contains(messagesYmlPath, " ") && getMessage(messagesYmlPath) != null) {
message = getMessage(messagesYmlPath);
else message = messagesYmlPath;
if (message.equalsIgnoreCase("") || messagesYmlPath.equalsIgnoreCase(""))
} else {
message = messagesYmlPath;
}
if (StringUtils.equalsIgnoreCase("", message) || StringUtils.equalsIgnoreCase("", messagesYmlPath)) {
return;
message = replacePlaceholders(message, additionalPlayerInfo);
p.sendMessage(message);
}
if (p instanceof Player player) {
UtilitiesOG.trueogMessage(player, expandPlaceholders(player, message, additionalPlayerInfo));
} else {
p.sendMessage(LegacyComponentSerializer.legacySection()
.serialize(expandPlaceholders(p, message, additionalPlayerInfo)));
}
}
public boolean canSee(Player viewer, Player viewed) {
if (!isPersistedVanished(viewed)) {
return true;
}
return !visibilityChanger.getHider().isHidden(viewed, viewer);
}
public void reconcileVisibility(Player subject) {
for (Player viewer : Bukkit.getOnlinePlayers()) {
reconcileVisibility(subject, viewer);
if (subject != viewer) {
reconcileVisibility(viewer, subject);
}
}
}
public void reconcileAllVisibilities() {
for (Player subject : Bukkit.getOnlinePlayers()) {
for (Player viewer : Bukkit.getOnlinePlayers()) {
reconcileVisibility(subject, viewer);
}
}
}
public void forceShowAllPlayers() {
forceShowAllPlayers(false);
}
/**
* @param aggressive when true, also clears legacy (null-plugin-ref) hide state
* left behind by plugins using the deprecated
* {@code Player#hidePlayer(Player)} API (Essentials is the
* common culprit). Only used by {@code /sv cleanup}, which is
* the documented escape hatch — normal reload/disable paths
* must not touch other plugins' hide state.
*/
public void forceShowAllPlayers(boolean aggressive) {
if (visibilityChanger == null) {
return;
}
for (Player subject : Bukkit.getOnlinePlayers()) {
for (Player viewer : Bukkit.getOnlinePlayers()) {
if (subject == viewer) {
continue;
}
if (aggressive) {
BukkitPlayerHidingUtil.showPlayerAggressive(subject, viewer, this);
} else {
BukkitPlayerHidingUtil.showPlayer(subject, viewer, this);
}
}
}
}
private void reconcileVisibility(Player subject, Player viewer) {
if (subject == viewer) {
return;
}
boolean hidden = isPersistedVanished(subject) && !hasPermissionToSee(viewer, subject);
visibilityChanger.getHider().setHidden(subject, viewer, hidden);
}
public boolean isPersistedVanished(Player player) {
return isPersistedVanished(player.getUniqueId());
}
public boolean isPersistedVanished(UUID uuid) {
return vanishStateMgr != null && vanishStateMgr.hasPersistedVanishEntry(uuid);
}
public boolean hasPermissionToVanish(CommandSender sender) {
return layeredPermissionChecker.hasPermissionToVanish(sender);
}
public boolean hasPermissionToSee(Player viewer, Player viewed) {
return layeredPermissionChecker.hasPermissionToSee(viewer, viewed);
}
public int getLayeredPermissionLevel(CommandSender sender, String permission) {
return layeredPermissionChecker.getLayeredPermissionLevel(sender, permission);
}
public FileConfiguration getSettings() {
return configMgr.getSettings();
}
public FileConfiguration getMessages() {
return configMgr.getMessages();
}
public FileConfiguration getPlayerData() {
return configMgr.getPlayerData();
return configMgr.getMessages();
}
@Override
public FileConfiguration getConfig() {
return getSettings();
}
@Override
public void log(Level level, String msg) {
getLogger().log(level, msg);
}
@Override
public void log(Level level, String msg, Throwable ex) {
getLogger().log(level, msg, ex);
}
@Override
public void logException(Throwable e) {
ExceptionLogger.logException(e, this);
}
}
public boolean isUseProtocolLib() {
return useProtocolLib;
}
public ActionBarMgr getActionBarMgr() {
return actionBarMgr;
}
@Override
public VanishStateMgr getVanishStateMgr() {
return vanishStateMgr;
}
public VersionUtil getVersionUtil() {
return versionUtil;
}
public ConfigMgr getConfigMgr() {
return configMgr;
}
public FeatureMgr getFeatureMgr() {
return featureMgr;
}
public PlaceholderConverter getPlaceholderConverter() {
return placeholderConverter;
}
public VanishCommand getCommand() {
return command;
}
public VisibilityChanger getVisibilityChanger() {
return visibilityChanger;
}
public LoginListener getLoginListener() {
return loginListener;
}
public LayeredPermissionChecker getLayeredPermissionChecker() {
return layeredPermissionChecker;
}
public PluginHookMgr getPluginHookMgr() {
return pluginHookMgr;
}
}
@@ -24,4 +24,5 @@ public interface SuperVanishPlugin {
void logException(Throwable e);
VanishStateMgr getVanishStateMgr();
}
@@ -10,51 +10,88 @@ package de.myzelyam.supervanish;
import org.bukkit.entity.Player;
import lombok.Getter;
import lombok.Setter;
import java.util.Objects;
import java.util.UUID;
/**
* Wrapped org.bukkit.entity.Player
* Holds additional information about players in the context of vanishing
*/
public class VanishPlayer {
private final SuperVanish plugin;
@Getter
private Player player;
@Setter
private final UUID playerUUID;
private boolean itemPickUps;
@Getter
private int seePermissionLevel, usePermissionLevel;
VanishPlayer(Player player, SuperVanish plugin, boolean itemPickUps) {
this.plugin = plugin;
this.player = player;
this.playerUUID = player.getUniqueId();
this.itemPickUps = itemPickUps;
if (plugin.getSettings().getBoolean("IndicationFeatures.LayeredPermissions.LayeredSeeAndUsePermissions", false)) {
if (plugin.getSettings().getBoolean("IndicationFeatures.LayeredPermissions.LayeredSeeAndUsePermissions",
false))
{
seePermissionLevel = plugin.getLayeredPermissionLevel(player, "see");
usePermissionLevel = plugin.getLayeredPermissionLevel(player, "use");
}
}
public boolean isOnlineVanished() {
return plugin.getVanishStateMgr().isVanished(player.getUniqueId());
return plugin.getVanishStateMgr().isVanished(playerUUID);
}
public boolean hasItemPickUpsEnabled() {
return itemPickUps;
}
public UUID getPlayerUUID() {
return playerUUID;
}
public void setItemPickUps(boolean itemPickUps) {
this.itemPickUps = itemPickUps;
}
public int getSeePermissionLevel() {
return seePermissionLevel;
}
public int getUsePermissionLevel() {
return usePermissionLevel;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
VanishPlayer that = (VanishPlayer) o;
return player != null ? player.getUniqueId().equals(that.player.getUniqueId()) : that.player == null;
return Objects.equals(playerUUID, that.playerUUID);
}
@Override
public int hashCode() {
return player != null ? player.getUniqueId().hashCode() : 0;
return Objects.hash(playerUUID);
}
}
@@ -16,89 +16,69 @@ import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public enum CommandAction {
VANISH_SELF(
"sv.use",
false,
"/sv [on|off]",
"Toggles your visibility") {
VANISH_SELF("sv.use", false, "/sv [on|off]", "Toggles your visibility") {
@Override
public boolean checkPermission(CommandSender sender, SuperVanish plugin) {
Validation.checkNotNull(plugin, "plugin cannot be null");
return plugin.hasPermissionToVanish(sender);
}
},
VANISH_OTHER(
"sv.others",
true,
"/sv [on|off] <player>",
"Shows or hides a player"),
VANISHED_LIST(
"sv.list",
true,
"/sv list",
"Shows a list of vanished players"),
BROADCAST_LOGIN(
"sv.login",
false,
"/sv login",
"Broadcasts a fake login message"),
BROADCAST_LOGOUT(
"sv.logout",
false,
"/sv logout",
"Broadcasts a fake logout message"),
TOGGLE_ITEM_PICKUPS(
"sv.toggleitems",
false,
"/sv tipu",
"Toggles picking up items") {
VANISH_OTHER("sv.others", true, "/sv [on|off] <player>", "Shows or hides a player"),
VANISHED_LIST("sv.list", true, "/sv list", "Shows a list of vanished players"),
BROADCAST_LOGIN("sv.login", false, "/sv login", "Broadcasts a fake login message"),
BROADCAST_LOGOUT("sv.logout", false, "/sv logout", "Broadcasts a fake logout message"),
TOGGLE_ITEM_PICKUPS("sv.toggleitems", false, "/sv tipu", "Toggles picking up items")
{
@Override
public boolean checkPermission(CommandSender sender, SuperVanish plugin) {
return sender.hasPermission(getMainPermission()) || sender.hasPermission("sv.toggleitempickups");
}
},
RECREATE_FILES(
"sv.recreatefiles",
true,
"/sv recreatefiles",
"Recreates the config") {
RECREATE_FILES("sv.recreatefiles", true, "/sv recreatefiles", "Recreates the config")
{
@Override
public boolean checkPermission(CommandSender sender, SuperVanish plugin) {
return sender.hasPermission(getMainPermission()) || sender.hasPermission("sv.updatecfg");
}
},
RELOAD(
"sv.reload",
true,
"/sv reload",
"Reloads all settings and messages"),
PRINT_STACKTRACE(
"sv.stacktrace",
true,
"/sv stacktrace",
"Logs info for a bug report"),
SHOW_HELP(
"sv.help",
true,
"/sv help",
"Shows this help page");
RELOAD("sv.reload", true, "/sv reload", "Reloads all settings and messages"),
CLEANUP("sv.cleanup", true, "/sv cleanup", "Clears all vanish state and forces everyone visible"),
PRINT_STACKTRACE("sv.stacktrace", true, "/sv stacktrace", "Logs info for a bug report"),
SHOW_HELP("sv.help", true, "/sv help", "Shows this help page");
/**
* Use {@link #checkPermission(CommandSender, SuperVanish)} to check whether a {@link CommandSender} has
* permission to perform an action or not
* Use {@link #checkPermission(CommandSender, SuperVanish)} to check whether a
* {@link CommandSender} has permission to perform an action or not
*/
@Getter
private final String mainPermission;
private final boolean console;
@Getter
private final String usage, description;
CommandAction(String mainPermission, boolean console, String usage, String description) {
this.mainPermission = mainPermission;
this.console = console;
this.usage = usage;
this.description = description;
}
static List<String> getAvailableFirstArguments(CommandSender sender, SuperVanish plugin) {
Validation.checkNotNull(plugin, "plugin cannot be null");
List<String> list = new ArrayList<>();
if (SHOW_HELP.checkPermission(sender, plugin))
@@ -107,6 +87,8 @@ public enum CommandAction {
list.add("recreatefiles");
if (RELOAD.checkPermission(sender, plugin))
list.add("reload");
if (CLEANUP.checkPermission(sender, plugin))
list.add("cleanup");
if (VANISHED_LIST.checkPermission(sender, plugin))
list.add("list");
if (VANISH_SELF.checkPermission(sender, plugin))
@@ -118,20 +100,46 @@ public enum CommandAction {
if (PRINT_STACKTRACE.checkPermission(sender, plugin))
list.add("stacktrace");
return list;
}
public static boolean hasAnyCmdPermission(CommandSender sender, SuperVanish plugin) {
for (CommandAction action : CommandAction.values())
if (action.checkPermission(sender, plugin))
return true;
return false;
}
public boolean checkPermission(CommandSender sender, SuperVanish plugin) {
return sender.hasPermission(getMainPermission());
}
public boolean usableByConsole() {
return console;
}
}
public String getMainPermission() {
return mainPermission;
}
public String getUsage() {
return usage;
}
public String getDescription() {
return description;
}
}
@@ -14,4 +14,5 @@ import org.bukkit.command.CommandSender;
public interface Executable {
void execute(Command cmd, CommandSender sender, String[] args, String label);
}
@@ -21,42 +21,61 @@ public abstract class SubCommand implements Executable {
protected final SuperVanish plugin;
public SubCommand(SuperVanish plugin) {
this.plugin = plugin;
}
protected Collection<UUID> getAllVanishedPlayers() {
return plugin.getVanishStateMgr().getVanishedPlayers();
}
protected Collection<UUID> getOnlineVanishedPlayers() {
return plugin.getVanishStateMgr().getOnlineVanishedPlayers();
}
public void hidePlayer(Player player) {
plugin.getVisibilityChanger().hidePlayer(player);
}
public void showPlayer(Player player) {
plugin.getVisibilityChanger().showPlayer(player);
}
public boolean isVanished(UUID uuid) {
return plugin.getVanishStateMgr().isVanished(uuid);
}
public boolean canDo(CommandSender sender, CommandAction action, boolean sendErrors) {
if (!(sender instanceof Player))
if (!action.usableByConsole()) {
if (sendErrors)
plugin.sendMessage(sender, "InvalidSender", sender);
return false;
}
if (!action.checkPermission(sender, plugin)) {
if (sendErrors)
plugin.sendMessage(sender, "NoPermission", sender);
return false;
}
return true;
}
}
@@ -25,120 +25,149 @@ public class SubCommandMgr {
private SuperVanish plugin;
public SubCommandMgr(SuperVanish plugin) {
this.plugin = plugin;
}
public void execute(Command cmd, CommandSender sender, String[] args, String label) {
try {
// invalid usage by default
Executable executable = new InvalidUsage(plugin);
// vanish self #1
if (args.length == 0) {
if (sender instanceof Player)
executable = new VanishSelf(plugin);
executable.execute(cmd, sender, args, label);
return;
}
// vanish other
if ((args[0].equalsIgnoreCase("on")
|| args[0].equalsIgnoreCase("off")
|| args[0].equalsIgnoreCase("vanish")
|| args[0].equalsIgnoreCase("reappear")
|| args[0].equalsIgnoreCase("enable")
|| args[0].equalsIgnoreCase("disable"))
&& args.length > 1
|| Bukkit.getPlayer(args[0]) != null) {
if ((args[0].equalsIgnoreCase("on") || args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("vanish")
|| args[0].equalsIgnoreCase("reappear") || args[0].equalsIgnoreCase("enable")
|| args[0].equalsIgnoreCase("disable")) && args.length > 1 || Bukkit.getPlayer(args[0]) != null)
{
executable = Bukkit.getPlayer(args[0]) != null
&& !(args[0].equalsIgnoreCase("on")
|| args[0].equalsIgnoreCase("off")
|| args[0].equalsIgnoreCase("vanish")
|| args[0].equalsIgnoreCase("reappear")
|| args[0].equalsIgnoreCase("enable")
|| args[0].equalsIgnoreCase("disable"))
? new VanishOther(Bukkit.getPlayer(args[0]), plugin)
: new VanishOther(plugin);
&& !(args[0].equalsIgnoreCase("on") || args[0].equalsIgnoreCase("off")
|| args[0].equalsIgnoreCase("vanish") || args[0].equalsIgnoreCase("reappear")
|| args[0].equalsIgnoreCase("enable") || args[0].equalsIgnoreCase("disable"))
? new VanishOther(Bukkit.getPlayer(args[0]), plugin)
: new VanishOther(plugin);
}
// vanish self #2
if ((args[0].equalsIgnoreCase("on")
|| args[0].equalsIgnoreCase("off")
|| args[0].equalsIgnoreCase("vanish")
|| args[0].equalsIgnoreCase("reappear")
|| args[0].equalsIgnoreCase("enable")
|| args[0].equalsIgnoreCase("disable")
|| args[0].equalsIgnoreCase("-s"))
&& args.length == 1) {
if ((args[0].equalsIgnoreCase("on") || args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("vanish")
|| args[0].equalsIgnoreCase("reappear") || args[0].equalsIgnoreCase("enable")
|| args[0].equalsIgnoreCase("disable") || args[0].equalsIgnoreCase("-s")) && args.length == 1)
{
executable = new VanishSelf(plugin);
}
//
if (args[0].equalsIgnoreCase("help")
|| args[0].equalsIgnoreCase("commands")
|| args[0].equalsIgnoreCase("?")) {
if (args[0].equalsIgnoreCase("help") || args[0].equalsIgnoreCase("commands")
|| args[0].equalsIgnoreCase("?"))
{
executable = new ShowHelp(plugin);
}
if (args[0].equalsIgnoreCase("printstacktrace")
|| args[0].equalsIgnoreCase("logstacktrace")
|| args[0].equalsIgnoreCase("dumpstacktrace")
|| args[0].equalsIgnoreCase("stacktrace")) {
if (args[0].equalsIgnoreCase("printstacktrace") || args[0].equalsIgnoreCase("logstacktrace")
|| args[0].equalsIgnoreCase("dumpstacktrace") || args[0].equalsIgnoreCase("stacktrace"))
{
executable = new PrintStacktrace(plugin);
}
if (args[0].equalsIgnoreCase("toggleitempickups")
|| args[0].equalsIgnoreCase("toggleitempickup")
|| args[0].equalsIgnoreCase("toggleitem")
|| args[0].equalsIgnoreCase("toggleitems")
|| args[0].equalsIgnoreCase("togglepickup")
|| args[0].equalsIgnoreCase("togglepickups")
|| args[0].equalsIgnoreCase("pickup")
|| args[0].equalsIgnoreCase("pickups")
|| args[0].equalsIgnoreCase("tipu")
|| args[0].equalsIgnoreCase("tip")) {
if (args[0].equalsIgnoreCase("toggleitempickups") || args[0].equalsIgnoreCase("toggleitempickup")
|| args[0].equalsIgnoreCase("toggleitem") || args[0].equalsIgnoreCase("toggleitems")
|| args[0].equalsIgnoreCase("togglepickup") || args[0].equalsIgnoreCase("togglepickups")
|| args[0].equalsIgnoreCase("pickup") || args[0].equalsIgnoreCase("pickups")
|| args[0].equalsIgnoreCase("tipu") || args[0].equalsIgnoreCase("tip"))
{
executable = new ToggleItemPickups(plugin);
}
if (args[0].equalsIgnoreCase("recreatecfg")
|| args[0].equalsIgnoreCase("rccfg")
|| args[0].equalsIgnoreCase("recreateconfig")
|| args[0].equalsIgnoreCase("rcconfig")
|| args[0].equalsIgnoreCase("updatecfg")
|| args[0].equalsIgnoreCase("recreate")
|| args[0].equalsIgnoreCase("recreatefiles")
|| args[0].equalsIgnoreCase("rf")
|| args[0].equalsIgnoreCase("rcf")
|| args[0].equalsIgnoreCase("refi")) {
if (args[0].equalsIgnoreCase("recreatecfg") || args[0].equalsIgnoreCase("rccfg")
|| args[0].equalsIgnoreCase("recreateconfig") || args[0].equalsIgnoreCase("rcconfig")
|| args[0].equalsIgnoreCase("updatecfg") || args[0].equalsIgnoreCase("recreate")
|| args[0].equalsIgnoreCase("recreatefiles") || args[0].equalsIgnoreCase("rf")
|| args[0].equalsIgnoreCase("rcf") || args[0].equalsIgnoreCase("refi"))
{
executable = new RecreateFiles(plugin);
}
if (args[0].equalsIgnoreCase("reload")
|| args[0].equalsIgnoreCase("rl")
|| args[0].equalsIgnoreCase("re")
|| args[0].equalsIgnoreCase("rlc")
|| args[0].equalsIgnoreCase("rlcfg")
|| args[0].equalsIgnoreCase("reloadconfig")
|| args[0].equalsIgnoreCase("rlp")
|| args[0].equalsIgnoreCase("rlpl")
|| args[0].equalsIgnoreCase("reloadplugin")) {
if (args[0].equalsIgnoreCase("reload") || args[0].equalsIgnoreCase("rl") || args[0].equalsIgnoreCase("re")
|| args[0].equalsIgnoreCase("rlc") || args[0].equalsIgnoreCase("rlcfg")
|| args[0].equalsIgnoreCase("reloadconfig") || args[0].equalsIgnoreCase("rlp")
|| args[0].equalsIgnoreCase("rlpl") || args[0].equalsIgnoreCase("reloadplugin"))
{
executable = new Reload(plugin);
}
if (args[0].equalsIgnoreCase("list")) {
executable = new VanishedList(plugin);
}
if (args[0].equalsIgnoreCase("cleanup") || args[0].equalsIgnoreCase("clearall")
|| args[0].equalsIgnoreCase("flush"))
{
executable = new Cleanup(plugin);
}
if (args[0].equalsIgnoreCase("login")) {
executable = new BroadcastLogin(plugin);
}
if (args[0].equalsIgnoreCase("logout")) {
executable = new BroadcastLogout(plugin);
}
executable.execute(cmd, sender, args, label);
} catch (Exception e) {
plugin.logException(e);
}
}
public List<String> onTabComplete(Command command, CommandSender sender,
String alias, String[] args) {
public List<String> onTabComplete(Command command, CommandSender sender, String alias, String[] args) {
// don't provide any help at all if user doesn't have permission to
// execute '/sv help'
if (!CommandAction.hasAnyCmdPermission(sender, plugin)) {
return Collections.emptyList();
}
if (args.length == 1) {
String toComplete = args[0];
// didn't start to type first argument
if (toComplete.equalsIgnoreCase(""))
@@ -146,34 +175,48 @@ public class SubCommandMgr {
// started to type it, only show args that start with given argument
List<String> matchingFirstArguments = new ArrayList<>();
for (String arg : CommandAction.getAvailableFirstArguments(sender, plugin)) {
if (arg.toLowerCase(Locale.ENGLISH).startsWith(toComplete.toLowerCase(Locale.ENGLISH)))
matchingFirstArguments.add(arg);
}
if (matchingFirstArguments.isEmpty())
return getOnlinePlayerNameTabCompletions(toComplete);
return matchingFirstArguments;
// extra commands
} else if (args.length == 2) {
// vanish other player tab completion
if ((args[0].equalsIgnoreCase("on")
|| args[0].equalsIgnoreCase("off")
|| args[0].equalsIgnoreCase("vanish")
|| args[0].equalsIgnoreCase("reappear")
|| args[0].equalsIgnoreCase("enable")
if ((args[0].equalsIgnoreCase("on") || args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("vanish")
|| args[0].equalsIgnoreCase("reappear") || args[0].equalsIgnoreCase("enable")
|| args[0].equalsIgnoreCase("disable"))
&& CommandAction.VANISH_OTHER.checkPermission(sender, plugin)) {
&& CommandAction.VANISH_OTHER.checkPermission(sender, plugin))
{
return getOnlinePlayerNameTabCompletions(args[1]);
}
}
return Collections.emptyList();
}
private List<String> getOnlinePlayerNameTabCompletions(String arg) {
List<String> playerNames = new ArrayList<>();
for (Player p : plugin.getServer().getOnlinePlayers()) {
if (p.getName().toLowerCase(Locale.ENGLISH).startsWith(arg.toLowerCase(Locale.ENGLISH)))
playerNames.add(p.getName());
}
return playerNames;
}
}
@@ -8,29 +8,33 @@
package de.myzelyam.supervanish.commands;
import de.myzelyam.supervanish.SuperVanish;
import java.util.List;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.List;
import de.myzelyam.supervanish.SuperVanish;
public class VanishCommand {
private final SuperVanish plugin;
private final SubCommandMgr subCommandMgr;
public VanishCommand(SuperVanish plugin) {
this.plugin = plugin;
subCommandMgr = new SubCommandMgr(plugin);
}
public void execute(Command command, CommandSender sender, String commandLabel, String[] args) {
subCommandMgr.execute(command, sender, args, commandLabel);
}
public List<String> tabComplete(Command command, CommandSender sender, String alias, String[] args)
throws IllegalArgumentException {
public List<String> tabComplete(Command command, CommandSender sender, String alias, String[] args) {
return subCommandMgr.onTabComplete(command, sender, alias, args);
}
}
}
@@ -20,14 +20,21 @@ import org.bukkit.entity.Player;
public class BroadcastLogin extends SubCommand {
public BroadcastLogin(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender p, String[] args, String label) {
if (canDo(p, CommandAction.BROADCAST_LOGIN, true)) {
for (Player onlinePlayer : Bukkit.getOnlinePlayers())
plugin.sendMessage(onlinePlayer, "ReappearMessage", p, onlinePlayer);
}
}
}
@@ -20,14 +20,21 @@ import org.bukkit.entity.Player;
public class BroadcastLogout extends SubCommand {
public BroadcastLogout(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender p, String[] args, String label) {
if (canDo(p, CommandAction.BROADCAST_LOGOUT, true)) {
for (Player onlinePlayer : Bukkit.getOnlinePlayers())
plugin.sendMessage(onlinePlayer, "VanishMessage", p, onlinePlayer);
}
}
}
@@ -0,0 +1,90 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.commands.subcommands;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.commands.CommandAction;
import de.myzelyam.supervanish.commands.SubCommand;
import net.trueog.utilitiesog.UtilitiesOG;
public class Cleanup extends SubCommand {
public Cleanup(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender p, String[] args, String label) {
if (!canDo(p, CommandAction.CLEANUP, true)) {
return;
}
plugin.getVanishStateMgr().clearAllVanishState();
// Must run before forceShowAllPlayers: Essentials' setVanished(false)
// internally calls the deprecated showPlayer(Player) for every online
// user, and we want our aggressive pass to finish after that so nothing
// sneaks back in.
if (plugin.getPluginHookMgr() != null) {
plugin.getPluginHookMgr().onCleanup();
}
if (plugin.getVisibilityChanger() != null) {
// Aggressive mode also drops the null-plugin-ref hide that Essentials
// and other deprecated-API users leave in CraftPlayer's
// invertedVisibilityEntities. Without it, CraftPlayer#canSee still
// returns false because the set for the target UUID is non-empty.
plugin.forceShowAllPlayers(true);
plugin.getVisibilityChanger().getHider().clearHiddenState();
}
for (Player online : Bukkit.getOnlinePlayers()) {
for (Plugin other : Bukkit.getPluginManager().getPlugins()) {
// Each plugin owns its own "vanished" metadata entry; leaving any
// of them populated keeps TAB-OG and other consumers treating the
// player as vanished even though Vanish-OG has been wiped.
online.removeMetadata("vanished", other);
}
}
plugin.reconcileAllVisibilities();
final String msg = "&aVanish state cleared. All players should now be visible and mutually damageable again.";
if (p instanceof Player player) {
UtilitiesOG.trueogMessage(player, msg);
} else {
p.sendMessage(msg);
}
}
}
@@ -18,15 +18,23 @@ import org.bukkit.command.CommandSender;
public class InvalidUsage extends SubCommand {
public InvalidUsage(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender sender, String[] args, String label) {
if (!CommandAction.hasAnyCmdPermission(sender, plugin)) {
plugin.sendMessage(sender, "NoPermission", sender);
return;
}
plugin.sendMessage(sender, "InvalidUsage", sender);
}
}
@@ -18,14 +18,21 @@ import org.bukkit.command.CommandSender;
public class PrintStacktrace extends SubCommand {
public PrintStacktrace(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender sender, String[] args, String label) {
if (canDo(sender, CommandAction.PRINT_STACKTRACE, true)) {
plugin.sendMessage(sender, "PrintedStacktrace", sender);
plugin.logException(null);
}
}
}
@@ -8,103 +8,136 @@
package de.myzelyam.supervanish.commands.subcommands;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.commands.CommandAction;
import de.myzelyam.supervanish.commands.SubCommand;
import java.io.File;
import org.bukkit.ChatColor;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.io.File;
import de.myzelyam.supervanish.PlaceholderConverter;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.commands.CommandAction;
import de.myzelyam.supervanish.commands.SubCommand;
import net.trueog.utilitiesog.UtilitiesOG;
public class RecreateFiles extends SubCommand {
public RecreateFiles(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender p, String[] args, String label) {
if (canDo(p, CommandAction.RECREATE_FILES, true)) {
String updates;
String changes;
if (plugin.getConfigMgr().isSettingsUpdateRequired()
&& plugin.getConfigMgr().isMessagesUpdateRequired()) {
updates = "the config and the messages file";
changes = "all settings and messages";
} else if (plugin.getConfigMgr().isSettingsUpdateRequired()) {
updates = "the config";
changes = "all settings";
} else {
updates = "the messages file";
changes = "all messages";
}
if (args.length != 2) {
if (!plugin.getConfigMgr().isSettingsUpdateRequired()
&& !plugin.getConfigMgr().isMessagesUpdateRequired()) {
plugin.sendMessage(p, "NoConfigUpdateAvailable", p);
return;
}
plugin.sendMessage(p, plugin.getMessage("UpdateWarning").replace("%changes%", changes)
.replace("%updates%", updates), p);
if (!canDo(p, CommandAction.RECREATE_FILES, true)) {
return;
}
String files = "the messages file";
String changes = "all messages";
if (args.length != 2) {
if (!plugin.getConfigMgr().isMessagesUpdateRequired()) {
plugin.sendMessage(p, "NoConfigUpdateAvailable", p);
return;
}
if (args[1].equalsIgnoreCase("confirm") || args[1].equalsIgnoreCase("force")) {
if (!plugin.getConfigMgr().isSettingsUpdateRequired()
&& !plugin.getConfigMgr().isMessagesUpdateRequired()
&& !args[1].equalsIgnoreCase("force")) {
plugin.sendMessage(p, "NoConfigUpdateAvailable", p);
return;
}
if (args[1].equalsIgnoreCase("force")) {
updates = "the config and the messages file";
changes = "all settings and messages";
}
// delete necessary files
boolean success = false;
if (plugin.getConfigMgr().isSettingsUpdateRequired()
|| args[1].equalsIgnoreCase("force")) {
File file = new File(plugin.getDataFolder().getPath() + File.separator + "config.yml");
success = file.delete();
plugin.getConfigMgr().getSettingsFile().save();
plugin.getConfigMgr().getSettingsFile().reload();
plugin.getConfigMgr().setSettings(plugin.getConfigMgr().getSettingsFile().getConfig());
}
if (plugin.getConfigMgr().isMessagesUpdateRequired()
|| args[1].equalsIgnoreCase("force")) {
File file2 = new File(plugin.getDataFolder().getPath() + File.separator + "messages.yml");
success &= file2.delete();
plugin.getConfigMgr().getMessagesFile().save();
plugin.getConfigMgr().getMessagesFile().reload();
plugin.getConfigMgr().setMessages(plugin.getConfigMgr().getMessagesFile().getConfig());
plugin.sendMessage(p, plugin.getMessage("UpdateWarning"), p,
PlaceholderConverter.placeholder("changes", changes),
PlaceholderConverter.placeholder("files", files));
return;
}
if (StringUtils.equalsIgnoreCase("confirm", args[1]) || StringUtils.equalsIgnoreCase(args[1], "force")) {
if (!plugin.getConfigMgr().isMessagesUpdateRequired() && !StringUtils.equalsIgnoreCase(args[1], "force")) {
plugin.sendMessage(p, "NoConfigUpdateAvailable", p);
return;
}
if (StringUtils.equalsIgnoreCase(args[1], "force")) {
files = "the config and the messages file";
changes = "all settings and messages";
}
// Delete necessary files.
boolean success = true;
if (StringUtils.equalsIgnoreCase(args[1], "force")) {
final File file = new File(plugin.getDataFolder().getPath() + File.separator + "config.yml");
success = file.delete();
plugin.getConfigMgr().getSettingsFile().save();
plugin.getConfigMgr().getSettingsFile().reload();
plugin.getConfigMgr().setSettings(plugin.getConfigMgr().getSettingsFile().getConfig());
}
if (plugin.getConfigMgr().isMessagesUpdateRequired() || StringUtils.equalsIgnoreCase(args[1], "force")) {
final File file2 = new File(plugin.getDataFolder().getPath() + File.separator + "messages.yml");
success &= file2.delete();
plugin.getConfigMgr().getMessagesFile().save();
plugin.getConfigMgr().getMessagesFile().reload();
plugin.getConfigMgr().setMessages(plugin.getConfigMgr().getMessagesFile().getConfig());
}
if (!success) {
final String failMsg = "&cERROR: Cannot recreate files because one of them could not be deleted. Are the file permissions valid?";
if (p instanceof Player player) {
UtilitiesOG.trueogMessage(player, failMsg);
} else {
p.sendMessage(failMsg);
}
if (!success) {
p.sendMessage(ChatColor.RED +
"Cannot update config, failed to delete file. Are the file permissions valid?");
return;
}
plugin.sendMessage(p, plugin.getMessage("RecreatedConfig")
.replace("%changes%", changes)
.replace("%updates%", updates), p);
// update update-information
plugin.getConfigMgr().checkFilesForLeftOvers();
} else if (args[1].equalsIgnoreCase("dismiss")) {
String currentVersion = plugin.getDescription().getVersion();
boolean isDismissed =
plugin.getPlayerData().getBoolean("PlayerData." + (p instanceof Player ? ((Player) p)
.getUniqueId()
.toString() : "CONSOLE") + ".dismissed." + currentVersion.replace(".", "_"), false);
plugin.getPlayerData().set("PlayerData." + (p instanceof Player ? ((Player) p).getUniqueId().toString()
: "CONSOLE") + ".dismissed." + currentVersion.replace(".", "_"), !isDismissed);
plugin.getConfigMgr().getPlayerDataFile().save();
if (!isDismissed)
plugin.sendMessage(p, "DismissedRecreationWarning", p);
else
plugin.sendMessage(p, "UndismissedRecreationWarning", p);
return;
}
plugin.sendMessage(p, plugin.getMessage("RecreatedConfig"), p,
PlaceholderConverter.placeholder("changes", changes),
PlaceholderConverter.placeholder("files", files));
// Refresh recreation status after regenerating the files.
plugin.getConfigMgr().checkFilesForLeftOvers();
} else if (StringUtils.equalsIgnoreCase("dismiss", args[1])) {
final String currentVersion = plugin.getPluginMeta().getVersion();
final String dismissId = p instanceof Player ? ((Player) p).getUniqueId().toString() : "CONSOLE";
final boolean isDismissed = plugin.getVanishStateMgr().isDismissed(dismissId, currentVersion);
plugin.getVanishStateMgr().setDismissed(dismissId, currentVersion, !isDismissed);
if (!isDismissed) {
plugin.sendMessage(p, "DismissedRecreationWarning", p);
} else {
plugin.sendMessage(p, "UndismissedRecreationWarning", p);
}
}
}
}
@@ -8,35 +8,57 @@
package de.myzelyam.supervanish.commands.subcommands;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import de.myzelyam.supervanish.PlaceholderConverter;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.commands.CommandAction;
import de.myzelyam.supervanish.commands.SubCommand;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import net.trueog.utilitiesog.UtilitiesOG;
public class Reload extends SubCommand {
public Reload(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender p, String[] args, String label) {
if (canDo(p, CommandAction.RELOAD, true)) {
long before = System.currentTimeMillis();
plugin.reload();
if (!Bukkit.getPluginManager().isPluginEnabled(plugin)) {
p.sendMessage(ChatColor.RED +
"Failed to reload SuperVanish since it failed to restart itself. " +
"More information is in the console. ("
+ (System.currentTimeMillis() - before) + "ms)");
return;
}
plugin.sendMessage(p, plugin.getMessage("PluginReloaded").replace("%time%",
(System.currentTimeMillis() - before) + ""), p);
if (!canDo(p, CommandAction.RELOAD, true)) {
return;
}
final long before = System.currentTimeMillis();
plugin.reload();
if (!Bukkit.getPluginManager().isPluginEnabled(plugin)) {
final String failMsg = "&cERROR: Failed to reload Vanish-OG since it failed to restart itself. "
+ "More information is in the console. (" + (System.currentTimeMillis() - before) + "ms)";
if (p instanceof Player player) {
UtilitiesOG.trueogMessage(player, failMsg);
} else {
p.sendMessage(failMsg);
}
return;
}
plugin.sendMessage(p, plugin.getMessage("PluginReloaded"), p,
PlaceholderConverter.placeholder("time", System.currentTimeMillis() - before));
}
}
@@ -8,7 +8,7 @@
package de.myzelyam.supervanish.commands.subcommands;
import de.myzelyam.supervanish.PlaceholderConverter;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.commands.CommandAction;
import de.myzelyam.supervanish.commands.SubCommand;
@@ -19,21 +19,32 @@ import org.bukkit.command.CommandSender;
public class ShowHelp extends SubCommand {
public ShowHelp(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender sender, String[] args, String label) {
if (canDo(sender, CommandAction.SHOW_HELP, true)) {
plugin.sendMessage(sender, "HelpHeader", sender);
for (CommandAction action : CommandAction.values()) {
if (canDo(sender, action, false)) {
plugin.sendMessage(sender, plugin.getMessage("HelpFormat")
.replace("%usage%", action.getUsage())
.replace("%description%", action.getDescription())
.replace("%permission%", action.getMainPermission()), sender);
plugin.sendMessage(sender, plugin.getMessage("HelpFormat"), sender,
PlaceholderConverter.placeholder("usage", action.getUsage()),
PlaceholderConverter.placeholder("description", action.getDescription()),
PlaceholderConverter.placeholder("permission", action.getMainPermission()));
}
}
}
}
}
@@ -20,31 +20,31 @@ import org.bukkit.entity.Player;
public class ToggleItemPickups extends SubCommand {
public ToggleItemPickups(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender sender, String[] args, String label) {
if (canDo(sender, CommandAction.TOGGLE_ITEM_PICKUPS, true)) {
Player p = (Player) sender;
plugin.sendMessage(p, plugin.getMessage("ToggledPickingUpItems"
+ (toggleState(plugin.getVanishPlayer(p)) ? "On" : "Off")), p);
plugin.sendMessage(p, plugin
.getMessage("ToggledPickingUpItems" + (toggleState(plugin.getVanishPlayer(p)) ? "On" : "Off")), p);
}
}
private boolean toggleState(VanishPlayer p) {
boolean hasEnabled = plugin.getPlayerData().getBoolean("PlayerData."
+ p.getPlayer().getUniqueId() + ".itemPickUps");
plugin.getPlayerData().set("PlayerData." + p.getPlayer().getUniqueId() + ".itemPickUps", !hasEnabled);
p.setItemPickUps(!hasEnabled);
plugin.getConfigMgr().getPlayerDataFile().save();
// fix /sv tipu
try {
//noinspection deprecation
p.getPlayer().spigot().setCollidesWithEntities(!hasEnabled);
} catch (NoClassDefFoundError | NoSuchMethodError ignored) {
}
//
private boolean toggleState(VanishPlayer vp) {
boolean hasEnabled = plugin.getVanishStateMgr().getItemPickUps(vp.getPlayerUUID(), false);
plugin.getVanishStateMgr().setItemPickUps(vp.getPlayerUUID(), !hasEnabled);
vp.setItemPickUps(!hasEnabled);
return !hasEnabled;
}
}
@@ -24,82 +24,126 @@ public class VanishOther extends SubCommand {
private Player specifiedPlayer;
public VanishOther(SuperVanish plugin) {
this(null, plugin);
}
public VanishOther(Player specifiedPlayer, SuperVanish plugin) {
super(plugin);
this.specifiedPlayer = specifiedPlayer;
}
@Override
public void execute(Command cmd, CommandSender sender, String[] args, String label) {
if (canDo(sender, CommandAction.VANISH_OTHER, true)) {
boolean hide = false, offline = false, silent = false;
Player target;
String name;
UUID uuid;
if (specifiedPlayer == null) {
if (args[0].equalsIgnoreCase("on") || args[0].equalsIgnoreCase("enable")
|| args[0].equalsIgnoreCase("vanish"))
hide = true;
target = Bukkit.getPlayer(args[1]);
name = target == null ? args[1] : target.getName();
} else {
target = specifiedPlayer;
name = specifiedPlayer.getName();
hide = !isVanished(target.getUniqueId());
}
if (target == null) {
offline = true;
uuid = plugin.getVanishStateMgr().getVanishedUUIDFromNameOnFile(name);
uuid = plugin.getVanishStateMgr().getVanishedUUIDFromName(name);
if (uuid == null) {
plugin.sendMessage(sender, "PlayerNonExistent", sender, name);
return;
}
} else {
name = target.getName();
uuid = target.getUniqueId();
}
if (!offline && sender instanceof Player && sender != target
&& target.hasPermission("sv.notoggle")) {
if (!offline && sender instanceof Player && sender != target && target.hasPermission("sv.notoggle")) {
plugin.sendMessage(sender, "CannotHideOtherPlayer", sender, name);
return;
}
if (plugin.getSettings().getBoolean(
"IndicationFeatures.LayeredPermissions.HideInvisibleInCommands", false) && target != null
&& sender instanceof Player && !plugin.hasPermissionToSee((Player) sender, target)) {
if (plugin.getSettings().getBoolean("IndicationFeatures.LayeredPermissions.HideInvisibleInCommands", false)
&& target != null && sender instanceof Player
&& !plugin.hasPermissionToSee((Player) sender, target))
{
plugin.sendMessage(sender, "PlayerNonExistent", sender, name);
return;
}
if (hide && (offline ? isVanished(uuid) : isVanished(uuid))) {
plugin.sendMessage(sender, "AlreadyInvisibleMessage", sender, name);
return;
} else if (!hide && !(offline ? isVanished(uuid) : isVanished(uuid))) {
plugin.sendMessage(sender, "AlreadyVisibleMessage", sender, name);
return;
}
if (args.length == 3)
silent = args[2].equalsIgnoreCase("-s");
else if (args.length == 2)
silent = args[1].equalsIgnoreCase("-s");
if (!offline) {
if (hide) {
plugin.getVisibilityChanger().hidePlayer(target, sender.getName(), silent);
plugin.sendMessage(sender, "HideOtherMessage", sender, name);
} else {
plugin.getVisibilityChanger().showPlayer(target, sender.getName());
plugin.sendMessage(sender, "ShowOtherMessage", sender, name, silent);
}
} else {
if (hide) {
plugin.getVanishStateMgr().setVanishedState(uuid, name, true, sender.getName());
plugin.sendMessage(sender, "HideOtherMessage", sender, name);
} else {
plugin.getVanishStateMgr().setVanishedState(uuid, name, false, sender.getName());
plugin.sendMessage(sender, "ShowOtherMessage", sender, name);
}
}
}
}
}
@@ -19,40 +19,63 @@ import org.bukkit.entity.Player;
public class VanishSelf extends SubCommand {
public VanishSelf(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, CommandSender s, String[] args, String label) {
if (canDo(s, CommandAction.VANISH_SELF, true)) {
Player p = (Player) s;
if (args.length == 0) {
if (isVanished(p.getUniqueId()))
showPlayer(p);
else
hidePlayer(p);
} else if (args.length == 1) {
if (args[0].equalsIgnoreCase("off")
|| args[0].equalsIgnoreCase("reappear")
|| args[0].equalsIgnoreCase("disable")) {
if (args[0].equalsIgnoreCase("off") || args[0].equalsIgnoreCase("reappear")
|| args[0].equalsIgnoreCase("disable"))
{
if (!isVanished(p.getUniqueId())) {
plugin.sendMessage(p, "NotVanishedError", p);
return;
}
showPlayer(p);
} else if (args[0].equalsIgnoreCase("-s")) {
if (isVanished(p.getUniqueId()))
plugin.getVisibilityChanger().showPlayer(p, null, true);
else
plugin.getVisibilityChanger().hidePlayer(p, null, true);
} else {
if (isVanished(p.getUniqueId())) {
plugin.sendMessage(p, "AlreadyVanishedError", p);
return;
}
hidePlayer(p);
}
}
}
}
}
@@ -10,12 +10,14 @@ package de.myzelyam.supervanish.commands.subcommands;
import com.google.common.collect.ImmutableList;
import de.myzelyam.supervanish.PlaceholderConverter;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.commands.CommandAction;
import de.myzelyam.supervanish.commands.SubCommand;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@@ -25,31 +27,53 @@ import java.util.UUID;
public class VanishedList extends SubCommand {
public VanishedList(SuperVanish plugin) {
super(plugin);
}
@Override
public void execute(Command cmd, final CommandSender sender, final String[] args, String label) {
if (canDo(sender, CommandAction.VANISHED_LIST, true)) {
String listMessage = plugin.getMessage("ListMessagePrefix");
StringBuilder stringBuilder = new StringBuilder();
List<UUID> allInvisiblePlayerUUIDs = ImmutableList.copyOf(getAllVanishedPlayers());
if (allInvisiblePlayerUUIDs.isEmpty()) {
stringBuilder.append("none");
}
for (int i = 0; i < allInvisiblePlayerUUIDs.size(); i++) {
UUID playerUUID = allInvisiblePlayerUUIDs.get(i);
String name = Bukkit.getOfflinePlayer(playerUUID).getName();
if (Bukkit.getPlayer(playerUUID) == null) {
name = name + ChatColor.RED + "[offline]" + ChatColor.WHITE;
}
stringBuilder.append(name);
if (i != allInvisiblePlayerUUIDs.size() - 1) {
stringBuilder.append(ChatColor.GREEN).append(", ").append(ChatColor.WHITE);
}
}
listMessage = listMessage.replace("%l", stringBuilder.toString());
plugin.sendMessage(sender, listMessage, sender);
if (!canDo(sender, CommandAction.VANISHED_LIST, true)) {
return;
}
String listMessage = plugin.getMessage("ListMessagePrefix");
final StringBuilder stringBuilder = new StringBuilder();
final List<UUID> allInvisiblePlayerUUIDs = ImmutableList.copyOf(getAllVanishedPlayers());
if (allInvisiblePlayerUUIDs.isEmpty()) {
stringBuilder.append("none");
}
for (int i = 0; i < allInvisiblePlayerUUIDs.size(); i++) {
final UUID playerUUID = allInvisiblePlayerUUIDs.get(i);
String name = Bukkit.getOfflinePlayer(playerUUID).getName();
if (Bukkit.getPlayer(playerUUID) == null) {
name = LegacyComponentSerializer.legacySection()
.serialize(MiniMessage.miniMessage().deserialize(name + "<red>[offline]<white>"));
}
stringBuilder.append(name);
if (i != allInvisiblePlayerUUIDs.size() - 1) {
stringBuilder.append(LegacyComponentSerializer.legacySection()
.serialize(MiniMessage.miniMessage().deserialize("<green>, <white>")));
}
}
plugin.sendMessage(sender, listMessage, sender,
PlaceholderConverter.placeholder("vanished_list", stringBuilder.toString()));
}
}
@@ -10,88 +10,128 @@ package de.myzelyam.supervanish.config;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.Collections;
import java.util.logging.Level;
import lombok.Data;
import static de.myzelyam.supervanish.SuperVanish.*;
@Data
public class ConfigMgr {
private final SuperVanish plugin;
private final FileMgr fileMgr;
private boolean settingsUpdateRequired, messagesUpdateRequired;
private FileConfiguration settings, messages, playerData;
private ConfigurableFile messagesFile, settingsFile;
private StorageFile playerDataFile;
private boolean messagesUpdateRequired;
private FileConfiguration settings;
private FileConfiguration messages;
private ConfigurableFile messagesFile;
private ConfigurableFile settingsFile;
public ConfigMgr(SuperVanish plugin) {
this.plugin = plugin;
fileMgr = new FileMgr(plugin);
}
public void prepareFiles() {
// messages
messagesFile = (ConfigurableFile) fileMgr.addFile("messages", FileMgr.FileType.CONFIG);
messagesFile = (ConfigurableFile) fileMgr.addFile("messages");
messages = messagesFile.getConfig();
// settings
settingsFile = (ConfigurableFile) fileMgr.addFile("config", FileMgr.FileType.CONFIG);
settingsFile = (ConfigurableFile) fileMgr.addFile("config");
settings = settingsFile.getConfig();
// data
playerDataFile = (StorageFile) fileMgr.addFile("data", FileMgr.FileType.STORAGE);
playerData = playerDataFile.getConfig();
playerData.addDefault("InvisiblePlayers", Collections.emptyList());
playerData.options().copyDefaults(true);
playerData.options().header("SuperVanish v" + plugin.getDescription().getVersion() + " - Data file");
playerDataFile.save();
checkFilesForLeftOvers();
}
public void checkFilesForLeftOvers() {
try {
String currentSettingsVersion = settings.getString("ConfigVersion");
String newestVersion = plugin.getDescription().getVersion();
String newestVersion = plugin.getPluginMeta().getVersion();
String currentMessagesVersion = messages.getString("MessagesVersion");
messagesUpdateRequired = fileRequiresRecreation(currentMessagesVersion, false);
settingsUpdateRequired = fileRequiresRecreation(currentSettingsVersion, true);
if (newestVersion.equals(currentSettingsVersion))
settingsUpdateRequired = false;
messagesUpdateRequired = fileRequiresRecreation(currentMessagesVersion);
if (newestVersion.equals(currentMessagesVersion))
messagesUpdateRequired = false;
if (settingsUpdateRequired || messagesUpdateRequired) {
String currentVersion = plugin.getDescription().getVersion();
boolean isDismissed = playerData.getBoolean("PlayerData.CONSOLE.dismissed."
+ currentVersion.replace(".", "_"), false);
if (!isDismissed) plugin.log(Level.WARNING, "At least one config file is outdated, " +
"it's recommended to regenerate it using '/sv recreatefiles'");
}
if (currentSettingsVersion.startsWith("1.5.") || currentSettingsVersion.startsWith("1.4.")) {
Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "You have a very outdated " +
"config file, your settings will not work until you regenerate your SV-files " +
"using /sv recreatefiles");
if (messagesUpdateRequired) {
String currentVersion = plugin.getPluginMeta().getVersion();
boolean isDismissed = plugin.getVanishStateMgr().isDismissed("CONSOLE", currentVersion);
if (!isDismissed)
plugin.log(Level.WARNING,
"Messages file needs to be recreated. " + "Use '/sv recreatefiles' to regenerate it.");
}
} catch (Exception e) {
plugin.logException(e);
}
}
private boolean fileRequiresRecreation(String currentVersion, boolean isSettingsFile) {
if (currentVersion == null) return true;
for (String ignoredVersion : isSettingsFile ? NON_REQUIRED_SETTINGS_UPDATES
: NON_REQUIRED_MESSAGES_UPDATES) {
if (currentVersion.equalsIgnoreCase(ignoredVersion)) return false;
private boolean fileRequiresRecreation(String currentVersion) {
if (currentVersion == null)
return true;
for (String ignoredVersion : NON_REQUIRED_MESSAGES_UPDATES) {
if (currentVersion.equalsIgnoreCase(ignoredVersion))
return false;
}
return true;
}
public FileMgr getFileMgr() {
return fileMgr;
}
public boolean isMessagesUpdateRequired() {
return messagesUpdateRequired;
}
public FileConfiguration getSettings() {
return settings;
}
public FileConfiguration getMessages() {
return messages;
}
public void setSettings(FileConfiguration settings) {
this.settings = settings;
}
public void setMessages(FileConfiguration messages) {
this.messages = messages;
}
public ConfigurableFile getMessagesFile() {
return messagesFile;
}
public ConfigurableFile getSettingsFile() {
return settingsFile;
}
}
@@ -27,47 +27,72 @@ public class ConfigurableFile implements PluginFile<FileConfiguration> {
private FileConfiguration defaultFileConfiguration;
public ConfigurableFile(String name, SuperVanish plugin) {
this.name = name + ".yml";
this.plugin = plugin;
setup();
}
@Override
public String getName() {
return name;
}
private void setup() {
file = new File(plugin.getDataFolder(), name);
try (Reader reader = new InputStreamReader(plugin.getResource(name))) {
defaultFileConfiguration = YamlConfiguration.loadConfiguration(reader);
} catch (IOException e) {
e.printStackTrace();
}
save();
}
@Override
public void reload() {
fileConfiguration = YamlConfiguration.loadConfiguration(file);
}
@Override
public FileConfiguration getConfig() {
if (fileConfiguration == null) {
reload();
}
return fileConfiguration;
}
@Override
public void save() {
if (!file.exists()) {
plugin.saveResource(name, false);
}
}
public FileConfiguration getDefaultConfig() {
return defaultFileConfiguration;
}
}
@@ -20,40 +20,37 @@ public class FileMgr {
private Map<String, PluginFile<?>> files;
public FileMgr(SuperVanishPlugin plugin) {
this.plugin = plugin;
files = new HashMap<>();
}
public PluginFile<?> addFile(String name, FileType type) {
public PluginFile<?> addFile(String name) {
if (name == null)
throw new IllegalArgumentException("The file name cannot be null!");
if (type == FileType.STORAGE) {
StorageFile file = new StorageFile(name, (SuperVanish) plugin);
files.put(name, file);
return file;
} else if (type == FileType.CONFIG) {
ConfigurableFile file = new ConfigurableFile(name, (SuperVanish) plugin);
files.put(name, file);
return file;
} else {
throw new IllegalArgumentException("The FileType cannot be null!");
}
ConfigurableFile file = new ConfigurableFile(name, (SuperVanish) plugin);
files.put(name, file);
return file;
}
public void reloadFile(String fileName) {
PluginFile<?> file = files.get(fileName);
if (file != null)
file.reload();
else
throw new IllegalArgumentException("Specified file doesn't exist!");
}
public void reloadAll() {
for (String fileName : files.keySet())
reloadFile(fileName);
}
public enum FileType {
STORAGE, CONFIG
}
}
@@ -17,4 +17,5 @@ public interface PluginFile<CT> {
CT getConfig();
void save();
}
@@ -1,62 +0,0 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.config;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
public class StorageFile implements PluginFile<FileConfiguration> {
private final SuperVanish plugin;
private String name;
private File file;
private FileConfiguration config;
public StorageFile(String name, SuperVanish plugin) {
this.name = name;
this.plugin = plugin;
setup();
}
@Override
public String getName() {
return name;
}
private void setup() {
file = new File(plugin.getDataFolder().getPath() + File.separator
+ name + ".yml");
config = YamlConfiguration.loadConfiguration(file);
save();
}
@Override
public void reload() {
setup();
}
@Override
public FileConfiguration getConfig() {
return config;
}
@Override
public void save() {
try {
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -1,117 +0,0 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.features;
import de.myzelyam.api.vanish.PlayerShowEvent;
import de.myzelyam.api.vanish.PostPlayerHideEvent;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
public class Broadcast extends Feature {
public Broadcast(SuperVanish plugin) {
super(plugin);
}
public static void announceSilentJoin(Player vanished, SuperVanish plugin) {
if (plugin.getSettings().getBoolean("MessageOptions.AnnounceRealJoinQuitToAdmins", true)) {
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (vanished == onlinePlayer)
continue;
if (plugin.canSee(onlinePlayer, vanished)) {
plugin.sendMessage(onlinePlayer, "SilentJoinMessageForAdmins", vanished, onlinePlayer);
}
}
}
}
public static void announceSilentDeath(Player p, SuperVanish plugin, String deathMessage) {
if (plugin.getSettings().getBoolean("MessageOptions.AnnounceDeathToAdmins", true)) {
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (p == onlinePlayer)
continue;
if (plugin.canSee(onlinePlayer, p)) {
String message = plugin.getMessage("SilentDeathMessage")
.replace("%deathmsg%", deathMessage);
plugin.sendMessage(onlinePlayer, message, p, onlinePlayer);
}
}
}
}
public static void announceSilentQuit(Player p, SuperVanish plugin) {
if (plugin.getSettings().getBoolean("MessageOptions.AnnounceRealJoinQuitToAdmins", true)) {
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (p == onlinePlayer)
continue;
if (plugin.canSee(onlinePlayer, p)) {
plugin.sendMessage(onlinePlayer, "SilentQuitMessageForAdmins", p, onlinePlayer);
}
}
}
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("MessageOptions.FakeJoinQuitMessages.BroadcastFakeQuitOnVanish")
|| plugin.getSettings().getBoolean("MessageOptions.FakeJoinQuitMessages" +
".BroadcastFakeQuitOnReappear");
}
@EventHandler
public void onVanish(PostPlayerHideEvent e) {
final Player p = e.getPlayer();
if (plugin.getSettings().getBoolean("MessageOptions.FakeJoinQuitMessages.BroadcastFakeQuitOnVanish")
&& !e.isSilent()) {
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (!plugin.canSee(onlinePlayer, p)) {
if (!plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.SendMessageOnlyToAdmins"))
plugin.sendMessage(onlinePlayer, "VanishMessage", p, onlinePlayer);
} else if (!plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.SendMessageOnlyToUsers"))
if (!plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.AnnounceVanishReappearToAdmins"))
plugin.sendMessage(onlinePlayer, "VanishMessage", p, onlinePlayer);
else if (onlinePlayer == p && !plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.SendMessageOnlyToAdmins"))
plugin.sendMessage(onlinePlayer, "VanishMessage", p, onlinePlayer);
else if (onlinePlayer != p)
plugin.sendMessage(onlinePlayer, "VanishMessageWithPermission", p, onlinePlayer);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PlayerShowEvent e) {
Player p = e.getPlayer();
if (plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.BroadcastFakeJoinOnReappear") && !e.isSilent()) {
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (!plugin.canSee(onlinePlayer, p)) {
if (!plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.SendMessageOnlyToAdmins"))
plugin.sendMessage(onlinePlayer, "ReappearMessage", p, onlinePlayer);
} else if (!plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.SendMessageOnlyToUsers"))
if (!plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.AnnounceVanishReappearToAdmins"))
plugin.sendMessage(onlinePlayer, "ReappearMessageWithPermission", p, onlinePlayer);
else if (onlinePlayer == p && !plugin.getSettings().getBoolean(
"MessageOptions.FakeJoinQuitMessages.SendMessageOnlyToAdmins"))
plugin.sendMessage(onlinePlayer, "ReappearMessage", p, onlinePlayer);
else if (onlinePlayer != p)
plugin.sendMessage(onlinePlayer, "ReappearMessageWithPermission", p, onlinePlayer);
}
}
}
}
@@ -20,18 +20,25 @@ public abstract class Feature implements Listener {
protected final SuperVanish plugin;
public Feature(SuperVanish plugin) {
this.plugin = plugin;
}
public void onEnable() {
}
public void onDisable() {
}
public abstract boolean isActive();
protected void delay(Runnable runnable) {
plugin.getServer().getScheduler().runTaskLater(plugin, runnable, 1);
}
}
@@ -8,12 +8,6 @@
package de.myzelyam.supervanish.features;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.utils.Requirement;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collection;
@@ -23,95 +17,149 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.utils.Requirement;
public class FeatureMgr {
private static Requirement<FeatureInfo> protocolLibInstalled = new Requirement<FeatureInfo>() {
@Override
public boolean fulfilledBy(FeatureInfo featureInfo) {
return Bukkit.getPluginManager().isPluginEnabled("ProtocolLib");
}
}, oneDotEightOrHigher = new Requirement<FeatureInfo>() {
@Override
public boolean fulfilledBy(FeatureInfo featureInfo) {
return featureInfo.getPlugin().getVersionUtil().isOneDotXOrHigher(8);
}
};
private static final Requirement<FeatureInfo> protocolLibInstalled = featureInfo -> Bukkit.getPluginManager()
.isPluginEnabled("ProtocolLib");
private static final Requirement<FeatureInfo> oneDotEightOrHigher = featureInfo -> featureInfo.getPlugin()
.getVersionUtil().isOneDotXOrHigher(8);
private static final Requirement<FeatureInfo> oneDotSeventeenOrHigher = featureInfo -> featureInfo.getPlugin()
.getVersionUtil().isOneDotXOrHigher(17);
private static final Requirement<FeatureInfo> supportedServer = featureInfo -> "Paper"
.equals(Bukkit.getServer().getName()) || "Purpur".equals(Bukkit.getServer().getName());
private final Map<String, FeatureInfo> registeredFeatures = new HashMap<>();
private final Set<Feature> activeFeatures = new HashSet<>();
private final SuperVanish plugin;
public FeatureMgr(SuperVanish plugin) {
this.plugin = plugin;
registeredFeatures.put("SilentOpenChest", new FeatureInfo(SilentOpenChest.class, plugin,
Arrays.asList(protocolLibInstalled, oneDotEightOrHigher)));
registeredFeatures.put("NightVision", new FeatureInfo(NightVision.class, plugin,
Arrays.asList(protocolLibInstalled, oneDotEightOrHigher)));
registeredFeatures.put("NightVision",
new FeatureInfo(NightVision.class, plugin, Arrays.asList(protocolLibInstalled, oneDotEightOrHigher)));
registeredFeatures.put("VanishIndication", new FeatureInfo(VanishIndication.class, plugin,
Arrays.asList(protocolLibInstalled, oneDotEightOrHigher)));
registeredFeatures.put("Broadcast", new FeatureInfo(Broadcast.class, plugin));
registeredFeatures.put("NoSculkSensorDetection", new FeatureInfo(NoSculkSensorDetection.class, plugin,
Collections.singletonList(oneDotSeventeenOrHigher)));
registeredFeatures.put("NoTurtleEggBreaking",
new FeatureInfo(NoTurtleEggBreaking.class, plugin, Collections.singletonList(oneDotSeventeenOrHigher)));
registeredFeatures.put("NoDripLeafTilt",
new FeatureInfo(NoDripLeafTilt.class, plugin, Collections.singletonList(oneDotSeventeenOrHigher)));
registeredFeatures.put("NoRaidTrigger",
new FeatureInfo(NoRaidTrigger.class, plugin, Collections.singletonList(oneDotSeventeenOrHigher)));
registeredFeatures.put("NoMobSpawn",
new FeatureInfo(NoMobSpawn.class, plugin, Collections.singletonList(supportedServer)));
}
public void enableFeatures() {
featureLoop:
for (String id : registeredFeatures.keySet()) {
FeatureInfo featureInfo = registeredFeatures.get(id);
featureLoop: for (String id : registeredFeatures.keySet()) {
final FeatureInfo featureInfo = registeredFeatures.get(id);
for (Requirement<FeatureInfo> requirement : featureInfo.getRequirements()) {
if (!requirement.fulfilledBy(featureInfo)) continue featureLoop;
if (!requirement.fulfilledBy(featureInfo)) {
continue featureLoop;
}
}
Feature feature;
final Feature feature;
try {
feature = featureInfo.getFeatureClass().getConstructor(SuperVanish.class).newInstance(plugin);
} catch (NoSuchMethodException | InvocationTargetException
| InstantiationException | IllegalAccessException e) {
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException
| IllegalAccessException e)
{
plugin.logException(e);
continue;
}
if (!feature.isActive()) continue;
if (!feature.isActive()) {
continue;
}
activeFeatures.add(feature);
Bukkit.getPluginManager().registerEvents(feature, plugin);
feature.onEnable();
}
}
public void disableFeatures() {
for (Feature feature : activeFeatures) {
activeFeatures.forEach(feature -> {
feature.onDisable();
HandlerList.unregisterAll(feature);
}
});
activeFeatures.clear();
}
@SuppressWarnings("unchecked")
public <T extends Feature> T getFeature(Class<T> featureClass) {
for (Feature feature : activeFeatures) {
if (feature.getClass().equals(featureClass)) {
//noinspection unchecked
return (T) feature;
}
}
return null;
// noinspection unchecked on purpose
return activeFeatures.stream().filter(feature -> feature.getClass().equals(featureClass)).findFirst()
.map(feature -> (T) feature).orElse(null);
}
public Set<Feature> getActiveFeatures() {
return activeFeatures;
}
@Data
private static class FeatureInfo {
private final Class<? extends Feature> featureClass;
private final Collection<Requirement<FeatureInfo>> requirements;
private final SuperVanish plugin;
FeatureInfo(Class<? extends Feature> featureClass, SuperVanish plugin,
Collection<Requirement<FeatureInfo>> requirements) {
this.featureClass = featureClass;
this.requirements = requirements;
this.plugin = plugin;
}
private record FeatureInfo(Class<? extends Feature> featureClass, SuperVanish plugin,
Collection<Requirement<FeatureInfo>> requirements)
{
FeatureInfo(Class<? extends Feature> featureClass, SuperVanish plugin) {
this(featureClass, plugin, Collections.<Requirement<FeatureInfo>>emptySet());
this(featureClass, plugin, Collections.emptySet());
}
public Class<? extends Feature> getFeatureClass() {
return featureClass;
}
public Collection<Requirement<FeatureInfo>> getRequirements() {
return requirements;
}
public SuperVanish getPlugin() {
return plugin;
}
}
}
@@ -8,8 +8,6 @@
package de.myzelyam.supervanish.features;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import de.myzelyam.api.vanish.PlayerHideEvent;
import de.myzelyam.api.vanish.PlayerShowEvent;
import de.myzelyam.supervanish.SuperVanish;
@@ -19,144 +17,153 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static com.comphenix.protocol.PacketType.Play.Server.ENTITY_EFFECT;
import static com.comphenix.protocol.PacketType.Play.Server.REMOVE_ENTITY_EFFECT;
public class NightVision extends Feature implements Runnable {
private boolean suppressErrors = false;
public static final int INFINITE_POTION_EFFECT_LENGTH = 32767;
private final Map<UUID, PotionEffect> playerPreviousPotionEffectMap = new HashMap<>();
public NightVision(SuperVanish plugin) {
super(plugin);
}
@Override
public void onEnable() {
plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, this, 20 * 60 * 2, 20 * 60 * 2);
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("InvisibilityFeatures.NightVisionEffect");
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVanish(PlayerHideEvent e) {
Player p = e.getPlayer();
sendAddPotionEffect(p, new PotionEffect(PotionEffectType.NIGHT_VISION,
INFINITE_POTION_EFFECT_LENGTH, 0));
// getPotionEffect(..) is 1.10+ API
if (plugin.getVersionUtil().isOneDotXOrHigher(10)) {
if (p.getPotionEffect(PotionEffectType.NIGHT_VISION) != null) {
playerPreviousPotionEffectMap.put(p.getUniqueId(), p.getPotionEffect(PotionEffectType.NIGHT_VISION));
}
}
sendAddPotionEffect(p);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PlayerShowEvent e) {
Player p = e.getPlayer();
sendRemovePotionEffect(p, PotionEffectType.NIGHT_VISION);
sendRemovePotionEffect(p);
if (playerPreviousPotionEffectMap.containsKey(p.getUniqueId())) {
p.addPotionEffect(playerPreviousPotionEffectMap.remove(p.getUniqueId()));
}
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
if (playerPreviousPotionEffectMap.containsKey(p.getUniqueId())) {
p.addPotionEffect(playerPreviousPotionEffectMap.remove(p.getUniqueId()));
}
} else {
sendAddPotionEffect(p);
}
}
@EventHandler
public void onQuit(PlayerQuitEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
sendAddPotionEffect(p, new PotionEffect(PotionEffectType.NIGHT_VISION,
INFINITE_POTION_EFFECT_LENGTH, 0));
sendRemovePotionEffect(p);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onTeleport(PlayerTeleportEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
if (e.getFrom().getWorld() == null || e.getTo() == null || e.getTo().getWorld() == null
|| e.getFrom().getWorld().getName().equals(e.getTo().getWorld().getName()))
return;
sendRemovePotionEffect(p);
}
@EventHandler
public void onWorldChange(PlayerChangedWorldEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
sendAddPotionEffect(p, new PotionEffect(PotionEffectType.NIGHT_VISION,
INFINITE_POTION_EFFECT_LENGTH, 0));
sendAddPotionEffect(p);
}
@Override
public void run() {
// renew every now and then to prevent blinking bug
for (UUID uuid : plugin.getVanishStateMgr().getOnlineVanishedPlayers()) {
Player p = Bukkit.getPlayer(uuid);
if (p == null) continue;
sendRemovePotionEffect(p, PotionEffectType.NIGHT_VISION);
sendAddPotionEffect(p, new PotionEffect(PotionEffectType.NIGHT_VISION,
INFINITE_POTION_EFFECT_LENGTH, 0));
if (p == null)
continue;
sendRemovePotionEffect(p);
sendAddPotionEffect(p);
}
}
private void sendAddPotionEffect(Player p, PotionEffect effect) {
PacketContainer packet = new PacketContainer(ENTITY_EFFECT);
//noinspection deprecation
int effectID = effect.getType().getId();
int amplifier = effect.getAmplifier();
int duration = effect.getDuration();
int entityID = p.getEntityId();
packet.getIntegers().write(0, entityID);
packet.getBytes().write(0, (byte) effectID);
packet.getBytes().write(1, (byte) amplifier);
packet.getIntegers().write(1, duration);
// hide particles in 1.9
packet.getBytes().write(2, (byte) 0);
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(p, packet);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot send packet", e);
} catch (Exception | NoClassDefFoundError e) {
if (!suppressErrors) {
plugin.logException(e);
plugin.getLogger().warning("IMPORTANT: Please make sure that you are using the latest " +
"dev-build of ProtocolLib and that your server is up-to-date! This error likely " +
"happened inside of ProtocolLib code which is out of SuperVanish's control. It's part " +
"of an optional feature module and can be removed safely by disabling " +
"NightVisionEffect in the config file. Please report this " +
"error if you can reproduce it on an up-to-date server with only latest " +
"ProtocolLib and latest SV installed.");
suppressErrors = true;
}
}
private void sendAddPotionEffect(Player p) {
p.addPotionEffect(
new PotionEffect(PotionEffectType.NIGHT_VISION, INFINITE_POTION_EFFECT_LENGTH, 0, true, false));
}
private void sendRemovePotionEffect(Player p, PotionEffectType type) {
PacketContainer packet = new PacketContainer(REMOVE_ENTITY_EFFECT);
//noinspection deprecation
final int effectID = type.getId();
final int entityID = p.getEntityId();
// 1.7 and below
if (!plugin.getVersionUtil().isOneDotXOrHigher(8)) {
packet.getIntegers().write(0, entityID);
packet.getBytes().write(0, (byte) effectID);
} else if (plugin.getVersionUtil().isOneDotX(8)) {
// 1.8
packet.getIntegers().write(0, entityID);
packet.getIntegers().write(1, effectID);
} else {
// 1.9 and higher
packet.getEffectTypes().write(0, type);
packet.getIntegers().write(0, entityID);
}
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(p, packet);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot send packet", e);
} catch (Exception | NoClassDefFoundError e) {
if (!suppressErrors) {
plugin.logException(e);
plugin.getLogger().warning("IMPORTANT: Please make sure that you are using the latest " +
"dev-build of ProtocolLib and that your server is up-to-date! This error likely " +
"happened inside of ProtocolLib code which is out of SuperVanish's control. It's part " +
"of an optional feature module and can be removed safely by disabling " +
"NightVisionEffect in the config file. Please report this " +
"error if you can reproduce it on an up-to-date server with only latest " +
"ProtocolLib and latest SV installed.");
suppressErrors = true;
}
}
private void sendRemovePotionEffect(Player p) {
p.removePotionEffect(PotionEffectType.NIGHT_VISION);
}
}
@@ -0,0 +1,38 @@
package de.myzelyam.supervanish.features;
import de.myzelyam.supervanish.SuperVanish;
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;
public class NoDripLeafTilt extends Feature {
public NoDripLeafTilt(SuperVanish plugin) {
super(plugin);
}
@EventHandler(priority = EventPriority.HIGH)
public void onInteract(PlayerInteractEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
if (!e.getAction().equals(Action.PHYSICAL) || e.getClickedBlock() == null
|| !e.getClickedBlock().getType().toString().equals("BIG_DRIPLEAF"))
return;
e.setCancelled(true);
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("InvisibilityFeatures.DisableDripLeaf", true);
}
}
@@ -0,0 +1,140 @@
package de.myzelyam.supervanish.features;
import com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent;
import com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent;
import com.destroystokyo.paper.event.entity.SkeletonHorseTrapEvent;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import java.util.List;
import java.util.UUID;
public class NoMobSpawn extends Feature {
private boolean suppressErrors = false;
public NoMobSpawn(SuperVanish plugin) {
super(plugin);
}
@EventHandler
public void onSkeletonHorseTrap(SkeletonHorseTrapEvent e) {
try {
List<HumanEntity> humans = e.getEligibleHumans();
int humansCount = humans.size();
for (HumanEntity human : humans) {
if (human instanceof Player) {
Player p = (Player) human;
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
humansCount--;
}
}
}
if (humansCount == 0)
e.setCancelled(true);
} catch (Exception er) {
if (!suppressErrors) {
plugin.logException(er);
suppressErrors = true;
}
}
}
@EventHandler
public void onEntitySpawn(PlayerNaturallySpawnCreaturesEvent e) {
try {
if (plugin.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId()))
e.setCancelled(true);
} catch (Exception er) {
if (!suppressErrors) {
plugin.logException(er);
suppressErrors = true;
}
}
}
@EventHandler
public void onEntitySpawnerSpawn(PreSpawnerSpawnEvent e) {
try {
// First check if a non-spectator vanished player is in range
boolean vanishedPlayerInRange = false;
for (UUID vanishedUUID : plugin.getVanishStateMgr().getOnlineVanishedPlayers()) {
Player p = Bukkit.getPlayer(vanishedUUID);
if (p == null)
continue;
if (p.getWorld().equals(e.getSpawnerLocation().getWorld())
&& p.getLocation().distanceSquared(e.getSpawnerLocation()) <= 256
&& p.getGameMode() != GameMode.SPECTATOR)
vanishedPlayerInRange = true;
}
if (!vanishedPlayerInRange)
return;
// If so, only cancel if no non-vanished player is in range
for (Player p : Bukkit.getOnlinePlayers()) {
if (p.getWorld().equals(e.getSpawnerLocation().getWorld())
&& p.getLocation().distanceSquared(e.getSpawnerLocation()) <= 256
&& p.getGameMode() != GameMode.SPECTATOR
&& !plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
}
e.setCancelled(true);
} catch (Exception er) {
if (!suppressErrors) {
plugin.logException(er);
suppressErrors = true;
}
}
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("InvisibilityFeatures.PreventMobSpawning", true);
}
}
@@ -23,56 +23,82 @@ import org.bukkit.scoreboard.Team;
public class NoPush extends Feature {
public NoPush(SuperVanish plugin) {
super(plugin);
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("InvisibilityFeatures.DisablePush");
}
public void setCantPush(Player p) {
Team team = p.getScoreboard().getTeam("Vanished");
if (team == null) {
team = p.getScoreboard().registerNewTeam("Vanished");
}
try {
team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
team.addEntry(p.getName());
} catch (NoSuchMethodError | NoClassDefFoundError ignored) {
}
}
public void setCanPush(Player p) {
Team team = p.getScoreboard().getTeam("Vanished");
if (team != null)
team.removeEntry(p.getName());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVanish(PlayerHideEvent e) {
setCantPush(e.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PlayerShowEvent e) {
setCanPush(e.getPlayer());
}
@EventHandler
public void onJoin(final PlayerJoinEvent e) {
if (plugin.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId()))
new BukkitRunnable() {
@Override
public void run() {
setCantPush(e.getPlayer());
}
}.runTaskLater(plugin, 5);
}
@EventHandler
public void onQuit(PlayerQuitEvent e) {
setCanPush(e.getPlayer());
}
}
@@ -0,0 +1,34 @@
package de.myzelyam.supervanish.features;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.raid.RaidTriggerEvent;
public class NoRaidTrigger extends Feature {
public NoRaidTrigger(SuperVanish plugin) {
super(plugin);
}
@EventHandler(priority = EventPriority.HIGH)
public void onInteract(RaidTriggerEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
e.setCancelled(true);
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("InvisibilityFeatures.PreventRaidTriggering", true);
}
}
@@ -0,0 +1,52 @@
package de.myzelyam.supervanish.features;
import de.myzelyam.supervanish.SuperVanish;
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.BlockReceiveGameEvent;
import org.bukkit.event.player.PlayerInteractEvent;
public class NoSculkSensorDetection extends Feature {
public NoSculkSensorDetection(SuperVanish plugin) {
super(plugin);
}
@EventHandler(priority = EventPriority.HIGH)
public void onSculkSensorTrigger(BlockReceiveGameEvent e) {
if (!(e.getEntity() instanceof Player))
return;
Player p = (Player) e.getEntity();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGH)
public void onInteract(PlayerInteractEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
if (!e.getAction().equals(Action.PHYSICAL) || e.getClickedBlock() == null)
return;
if (!e.getClickedBlock().getType().toString().matches("SCULK_SENSOR|CALIBRATED_SCULK_SENSOR|SCULK_SHRIEKER"))
return;
e.setCancelled(true);
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("InvisibilityFeatures.PreventSculkSensorActivation", true);
}
}
@@ -0,0 +1,38 @@
package de.myzelyam.supervanish.features;
import de.myzelyam.supervanish.SuperVanish;
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;
public class NoTurtleEggBreaking extends Feature {
public NoTurtleEggBreaking(SuperVanish plugin) {
super(plugin);
}
@EventHandler(priority = EventPriority.HIGH)
public void onInteract(PlayerInteractEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
if (!e.getAction().equals(Action.PHYSICAL) || e.getClickedBlock() == null
|| !e.getClickedBlock().getType().toString().equals("TURTLE_EGG"))
return;
e.setCancelled(true);
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("InvisibilityFeatures.PreventTurtleEggBreaking", true);
}
}
@@ -8,9 +8,34 @@
package de.myzelyam.supervanish.features;
import com.comphenix.protocol.ProtocolLibrary;
import de.myzelyam.api.vanish.PlayerShowEvent;
import de.myzelyam.supervanish.SuperVanish;
import static org.bukkit.Material.BLACK_SHULKER_BOX;
import static org.bukkit.Material.BLUE_SHULKER_BOX;
import static org.bukkit.Material.BROWN_SHULKER_BOX;
import static org.bukkit.Material.CHEST;
import static org.bukkit.Material.CYAN_SHULKER_BOX;
import static org.bukkit.Material.ENDER_CHEST;
import static org.bukkit.Material.GRAY_SHULKER_BOX;
import static org.bukkit.Material.GREEN_SHULKER_BOX;
import static org.bukkit.Material.ITEM_FRAME;
import static org.bukkit.Material.LIGHT_BLUE_SHULKER_BOX;
import static org.bukkit.Material.LIGHT_GRAY_SHULKER_BOX;
import static org.bukkit.Material.LIME_SHULKER_BOX;
import static org.bukkit.Material.MAGENTA_SHULKER_BOX;
import static org.bukkit.Material.ORANGE_SHULKER_BOX;
import static org.bukkit.Material.PINK_SHULKER_BOX;
import static org.bukkit.Material.PURPLE_SHULKER_BOX;
import static org.bukkit.Material.RED_SHULKER_BOX;
import static org.bukkit.Material.SHULKER_BOX;
import static org.bukkit.Material.TRAPPED_CHEST;
import static org.bukkit.Material.WHITE_SHULKER_BOX;
import static org.bukkit.Material.YELLOW_SHULKER_BOX;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -22,15 +47,22 @@ import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.player.*;
import org.bukkit.event.player.PlayerGameModeChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import java.util.*;
import com.comphenix.protocol.ProtocolLibrary;
import static org.bukkit.Material.*;
import de.myzelyam.api.vanish.PlayerShowEvent;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.hooks.OpenInvHook;
public class SilentOpenChest extends Feature {
@@ -39,215 +71,386 @@ public class SilentOpenChest extends Feature {
private final Collection<Material> additionalChestMaterials;
public SilentOpenChest(SuperVanish plugin) {
super(plugin);
additionalChestMaterials = new ArrayList<>();
if (plugin.getVersionUtil().isOneDotXOrHigher(11)) {
try {
//noinspection unused
InventoryType testInvType = InventoryType.SHULKER_BOX;
additionalChestMaterials.addAll(Arrays.asList(BLACK_SHULKER_BOX, BLUE_SHULKER_BOX, BROWN_SHULKER_BOX,
CYAN_SHULKER_BOX, GRAY_SHULKER_BOX, GREEN_SHULKER_BOX, LIGHT_BLUE_SHULKER_BOX,
LIME_SHULKER_BOX, MAGENTA_SHULKER_BOX, ORANGE_SHULKER_BOX, PINK_SHULKER_BOX,
PURPLE_SHULKER_BOX, RED_SHULKER_BOX, WHITE_SHULKER_BOX,
YELLOW_SHULKER_BOX));
CYAN_SHULKER_BOX, GRAY_SHULKER_BOX, GREEN_SHULKER_BOX, LIGHT_BLUE_SHULKER_BOX, LIME_SHULKER_BOX,
MAGENTA_SHULKER_BOX, ORANGE_SHULKER_BOX, PINK_SHULKER_BOX, PURPLE_SHULKER_BOX, RED_SHULKER_BOX,
WHITE_SHULKER_BOX, YELLOW_SHULKER_BOX));
try {
additionalChestMaterials.add(LIGHT_GRAY_SHULKER_BOX);
} catch (NoSuchFieldError e) {
// old name
// Old name.
additionalChestMaterials.add(Material.valueOf("SILVER_SHULKER_BOX"));
}
try {
additionalChestMaterials.add(SHULKER_BOX);
} catch (NoSuchFieldError ignored) {
// no standard shulker box in old versions
}
if (plugin.getVersionUtil().isOneDotXOrHigher(14)) {
additionalChestMaterials.add(Material.valueOf("BARREL"));
}
} catch (NoSuchFieldError | IllegalArgumentException ignored) {
// no shulker box support in very old versions
}
}
}
@Override
public void onDisable() {
for (Player p : playerStateInfoMap.keySet()) {
StateInfo stateInfo = playerStateInfoMap.remove(p);
if (stateInfo == null) continue;
final StateInfo stateInfo = playerStateInfoMap.remove(p);
if (stateInfo == null) {
continue;
}
restoreState(stateInfo, p);
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onSpectatorClick(InventoryClickEvent e) {
if (!(e.getWhoClicked() instanceof Player))
if (!(e.getWhoClicked() instanceof Player)) {
return;
Player p = (Player) e.getWhoClicked();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId())) return;
if (!playerStateInfoMap.containsKey(p)) return;
if (p.getGameMode() == GameMode.SPECTATOR) {
e.setCancelled(false);
}
final Player p = (Player) e.getWhoClicked();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
return;
}
if (!playerStateInfoMap.containsKey(p)) {
return;
}
if (p.getGameMode() == GameMode.SPECTATOR) {
e.setCancelled(false);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onQuit(PlayerQuitEvent e) {
Player p = e.getPlayer();
StateInfo stateInfo = playerStateInfoMap.remove(p);
if (stateInfo == null) return;
final Player p = e.getPlayer();
final StateInfo stateInfo = playerStateInfoMap.remove(p);
if (stateInfo == null) {
return;
}
restoreState(stateInfo, p);
playerStateInfoMap.remove(p);
}
@EventHandler(priority = EventPriority.HIGH)
public void onTeleport(PlayerTeleportEvent e) {
Player p = e.getPlayer();
if (playerStateInfoMap.containsKey(p)
&& e.getCause() == PlayerTeleportEvent.TeleportCause.SPECTATE) {
final Player p = e.getPlayer();
if (playerStateInfoMap.containsKey(p) && e.getCause() == PlayerTeleportEvent.TeleportCause.SPECTATE) {
e.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PlayerShowEvent e) {
Player p = e.getPlayer();
StateInfo stateInfo = playerStateInfoMap.remove(p);
if (stateInfo == null) return;
final Player p = e.getPlayer();
final StateInfo stateInfo = playerStateInfoMap.remove(p);
if (stateInfo == null) {
return;
}
p.closeInventory();
restoreState(stateInfo, p);
playerStateInfoMap.remove(p);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onMove(PlayerMoveEvent e) {
Player p = e.getPlayer();
if (playerStateInfoMap.containsKey(p)) {
Location loc = e.getTo() != null ? e.getTo() : e.getFrom();
if (playerStateInfoMap.get(p).openLoc.distance(loc) > .5) {
p.closeInventory();
restoreState(playerStateInfoMap.get(p), p);
playerStateInfoMap.remove(p);
}
final Player p = e.getPlayer();
if (!playerStateInfoMap.containsKey(p)) {
return;
}
final Location loc = e.getTo() != null ? e.getTo() : e.getFrom();
if (playerStateInfoMap.get(p).openLoc.distance(loc) <= .5) {
return;
}
p.closeInventory();
restoreState(playerStateInfoMap.get(p), p);
playerStateInfoMap.remove(p);
}
@EventHandler(priority = EventPriority.HIGH)
@EventHandler(priority = EventPriority.NORMAL)
public void onGameModeChange(PlayerGameModeChangeEvent e) {
Player p = e.getPlayer();
if (playerStateInfoMap.containsKey(p) && e.getNewGameMode() != GameMode.SPECTATOR) {
// Don't let low-priority event listeners cancel the gamemode change
if (e.isCancelled()) e.setCancelled(false);
final Player p = e.getPlayer();
final boolean condition = playerStateInfoMap.containsKey(p) && e.getNewGameMode() != GameMode.SPECTATOR
&& e.isCancelled();
// Don't let low-priority event listeners cancel the gamemode change.
if (condition) {
e.setCancelled(false);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onChestInteract(PlayerInteractEvent e) {
Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId())
|| !p.hasPermission("sv.silentchest")) return;
if (e.getAction() != Action.RIGHT_CLICK_BLOCK) return;
if (p.getGameMode() == GameMode.SPECTATOR) return;
//noinspection deprecation
if (p.isSneaking() && p.getItemInHand() != null
&& (p.getItemInHand().getType().isBlock() || p.getItemInHand().getType() == ITEM_FRAME)
&& p.getItemInHand().getType() != Material.AIR)
final Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()) || !p.hasPermission("sv.silentchest")) {
return;
Block block = e.getClickedBlock();
if (block == null) return;
}
if (e.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
if (p.getGameMode() == GameMode.SPECTATOR) {
return;
}
final ItemStack heldItem = p.getInventory().getItemInMainHand();
if (p.isSneaking() && heldItem != null && (heldItem.getType().isBlock() || heldItem.getType() == ITEM_FRAME)
&& heldItem.getType() != Material.AIR)
{
return;
}
final Block block = e.getClickedBlock();
if (block == null) {
return;
}
if (block.getType() == ENDER_CHEST) {
e.setCancelled(true);
p.openInventory(p.getEnderChest());
return;
}
if (!(block.getType() == CHEST || block.getType() == TRAPPED_CHEST
|| plugin.getVersionUtil().isOneDotXOrHigher(11) && additionalChestMaterials.contains(block.getType())))
{
return;
StateInfo stateInfo = StateInfo.extract(p);
}
final StateInfo stateInfo = StateInfo.extract(p);
p.setVelocity(new Vector(0, 0, 0));
playerStateInfoMap.put(p, stateInfo);
p.setGameMode(GameMode.SPECTATOR);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onChestClose(InventoryCloseEvent e) {
if (!(e.getPlayer() instanceof Player))
if (!(e.getPlayer() instanceof Player)) {
return;
}
final Player p = (Player) e.getPlayer();
if (!playerStateInfoMap.containsKey(p)) return;
if (!playerStateInfoMap.containsKey(p)) {
return;
}
if (!isSilentOpenInventory(e.getView())) {
return;
}
new BukkitRunnable() {
@Override
public void run() {
StateInfo stateInfo = playerStateInfoMap.get(p);
if (stateInfo == null) return;
final StateInfo stateInfo = playerStateInfoMap.get(p);
if (stateInfo == null) {
return;
}
restoreState(stateInfo, p);
playerStateInfoMap.remove(p);
}
}.runTaskLater(plugin, 1);
}
private void restoreState(StateInfo stateInfo, Player p) {
p.setGameMode(stateInfo.gameMode);
p.teleport(p.getLocation().add(0, 0.2, 0));
new BukkitRunnable() {
@Override
public void run() {
p.setAllowFlight(stateInfo.canFly);
p.setFlying(stateInfo.isFlying);
}
}.runTaskLater(plugin, 1);
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("InvisibilityFeatures.OpenChestsSilently");
return plugin.getSettings().getBoolean("InvisibilityFeatures.OpenChestsSilently")
&& !(plugin.getPluginHookMgr() != null && plugin.getPluginHookMgr().isHookActive(OpenInvHook.class));
}
private boolean isShulkerBox(Inventory inv) {
try {
return inv.getType() == InventoryType.SHULKER_BOX;
} catch (NoSuchFieldError e) {
return false;
}
}
private boolean isShulkerBox(InventoryView inv) {
return isShulkerBox(inv.getTopInventory());
}
private boolean isBarrel(InventoryView inv) {
try {
return inv.getType() == InventoryType.SHULKER_BOX;
return inv.getType() == InventoryType.BARREL;
} catch (NoSuchFieldError e) {
return false;
}
}
private boolean isSilentOpenInventory(InventoryView inv) {
return inv.getType() == InventoryType.CHEST || inv.getType() == InventoryType.ENDER_CHEST || isShulkerBox(inv)
|| isBarrel(inv);
}
public boolean hasSilentlyOpenedChest(Player p) {
return playerStateInfoMap.containsKey(p);
}
@Override
public void onEnable() {
SilentOpenChestPacketAdapter packetAdapter = new SilentOpenChestPacketAdapter(this);
// ProtocolLib 5.0 maps PLAYER_INFO to ClientboundPlayerInfoUpdatePacket
final SilentOpenChestPacketAdapter packetAdapter = new SilentOpenChestPacketAdapter(this);
ProtocolLibrary.getProtocolManager().addPacketListener(packetAdapter);
}
private static class StateInfo {
private final boolean canFly, isFlying;
private final GameMode gameMode;
private final Location openLoc;
StateInfo(boolean canFly, boolean isFlying, GameMode gameMode, Location openLoc) {
this.canFly = canFly;
this.isFlying = isFlying;
this.gameMode = gameMode;
this.openLoc = openLoc;
}
private record StateInfo(boolean canFly, boolean isFlying, GameMode gameMode, Location openLoc) {
static StateInfo extract(Player p) {
return new StateInfo(
p.getAllowFlight(),
p.isFlying(),
p.getGameMode(),
p.getLocation()
);
return new StateInfo(p.getAllowFlight(), p.isFlying(), p.getGameMode(), p.getLocation());
}
}
}
@@ -2,7 +2,7 @@
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* license, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
@@ -20,9 +20,18 @@ import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import static com.comphenix.protocol.PacketType.Play.Server.*;
/**
* Adapter that masks a vanished player's silent-chest spectator state from
* other clients. On Purpur 1.19.4 ProtocolLib's PLAYER_INFO type maps to
* ClientboundPlayerInfoUpdatePacket which carries a Set<Action> instead of the
* legacy single action; ViaSuite handles client-side re-encoding for connected
* versions 1.8-1.21.x.
*/
public class SilentOpenChestPacketAdapter extends PacketAdapter {
private final SilentOpenChest silentOpenChest;
@@ -30,90 +39,167 @@ public class SilentOpenChestPacketAdapter extends PacketAdapter {
private boolean suppressErrors = false;
public SilentOpenChestPacketAdapter(SilentOpenChest silentOpenChest) {
super(silentOpenChest.plugin, ListenerPriority.LOW, PLAYER_INFO, ABILITIES,
ENTITY_METADATA);
super(silentOpenChest.plugin, ListenerPriority.LOW, PLAYER_INFO, ABILITIES, ENTITY_METADATA);
this.silentOpenChest = silentOpenChest;
}
@Override
public void onPacketSending(PacketEvent event) {
try {
Player receiver = event.getPlayer();
if (receiver == null) return;
if (receiver == null)
return;
if (event.getPacketType() == PLAYER_INFO) {
// multiple events share same packet object
event.setPacket(event.getPacket().shallowClone());
List<PlayerInfoData> infoDataList = new ArrayList<>(
event.getPacket().getPlayerInfoDataLists().read(0));
if (!isGameModeUpdate(event))
return;
List<PlayerInfoData> infoDataList = new ArrayList<>(event.getPacket().getPlayerInfoDataLists().read(0));
boolean modified = false;
for (PlayerInfoData infoData : ImmutableList.copyOf(infoDataList)) {
if (!silentOpenChest.plugin.getVisibilityChanger().getHider()
.isHidden(infoData.getProfile().getUUID(), receiver)
&& silentOpenChest.plugin.getVanishStateMgr()
.isVanished(infoData.getProfile().getUUID())) {
Player vanishedTabPlayer = Bukkit.getPlayer(infoData.getProfile().getUUID());
if (infoData.getGameMode() == EnumWrappers.NativeGameMode.SPECTATOR
&& silentOpenChest.hasSilentlyOpenedChest(vanishedTabPlayer)
&& event.getPacket().getPlayerInfoAction().read(0)
== EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE) {
int latency;
try {
latency = infoData.getLatency();
} catch (NoSuchMethodError e) {
latency = 21;
}
PlayerInfoData newData = new PlayerInfoData(infoData.getProfile(),
latency, EnumWrappers.NativeGameMode.SURVIVAL,
infoData.getDisplayName());
infoDataList.remove(infoData);
infoDataList.add(newData);
}
}
UUID uuid = extractUUID(infoData);
if (uuid == null)
continue;
if (silentOpenChest.plugin.getVisibilityChanger().getHider().isHidden(uuid, receiver))
continue;
if (!silentOpenChest.plugin.getVanishStateMgr().isVanished(uuid))
continue;
if (infoData.getGameMode() != EnumWrappers.NativeGameMode.SPECTATOR)
continue;
Player vanishedTabPlayer = Bukkit.getPlayer(uuid);
if (vanishedTabPlayer == null || !silentOpenChest.hasSilentlyOpenedChest(vanishedTabPlayer))
continue;
PlayerInfoData newData = new PlayerInfoData(uuid, infoData.getLatency(), infoData.isListed(),
EnumWrappers.NativeGameMode.SURVIVAL, infoData.getProfile(), infoData.getDisplayName(),
infoData.getRemoteChatSessionData());
int index = infoDataList.indexOf(infoData);
infoDataList.set(index, newData);
modified = true;
}
event.getPacket().getPlayerInfoDataLists().write(0, infoDataList);
if (modified)
event.getPacket().getPlayerInfoDataLists().write(0, infoDataList);
} else if (event.getPacketType() == GAME_STATE_CHANGE) {
// Currently unused due to ProtocolLib class loading bug
if (silentOpenChest.plugin.getVanishStateMgr().isVanished(
receiver.getUniqueId())) {
if (silentOpenChest.plugin.getVanishStateMgr().isVanished(receiver.getUniqueId())) {
try {
if (event.getPacket().getIntegers().read(0) != 3) return;
if (event.getPacket().getIntegers().read(0) != 3)
return;
} catch (FieldAccessException e) {
// TODO
}
if (!silentOpenChest.hasSilentlyOpenedChest(receiver)) return;
if (!silentOpenChest.hasSilentlyOpenedChest(receiver))
return;
event.setCancelled(true);
}
} else if (event.getPacketType() == ABILITIES) {
if (silentOpenChest.plugin.getVanishStateMgr().isVanished(
receiver.getUniqueId())) {
if (!silentOpenChest.hasSilentlyOpenedChest(receiver)) return;
if (silentOpenChest.plugin.getVanishStateMgr().isVanished(receiver.getUniqueId())) {
if (!silentOpenChest.hasSilentlyOpenedChest(receiver))
return;
event.setCancelled(true);
}
} else if (event.getPacketType() == ENTITY_METADATA) {
int entityID = event.getPacket().getIntegers().read(0);
if (entityID == receiver.getEntityId()) {
if (silentOpenChest.plugin.getVanishStateMgr().isVanished(
receiver.getUniqueId())) {
if (!silentOpenChest.hasSilentlyOpenedChest(receiver)) return;
if (silentOpenChest.plugin.getVanishStateMgr().isVanished(receiver.getUniqueId())) {
if (!silentOpenChest.hasSilentlyOpenedChest(receiver))
return;
event.setCancelled(true);
}
}
}
} catch (Exception | NoClassDefFoundError e) {
if (!suppressErrors) {
if (e.getMessage() == null
|| !e.getMessage().endsWith("is not supported for temporary players.")) {
if (e.getMessage() == null || !e.getMessage().endsWith("is not supported for temporary players.")) {
silentOpenChest.plugin.logException(e);
silentOpenChest.plugin.getLogger().warning("IMPORTANT: Please make sure that you are using the latest " +
"dev-build of ProtocolLib and that your server is up-to-date! This error likely " +
"happened inside of ProtocolLib code which is out of SuperVanish's control. It's part " +
"of an optional feature module and can be removed safely by disabling " +
"OpenChestsSilently in the config file. Please report this " +
"error if you can reproduce it on an up-to-date server with only latest " +
"ProtocolLib and latest SV installed.");
silentOpenChest.plugin.getLogger()
.warning("IMPORTANT: Please make sure that you are using the latest "
+ "dev-build of ProtocolLib and that your server is up-to-date! This error likely "
+ "happened inside of ProtocolLib code which is out of Vanish-OG's control. It's part "
+ "of an optional feature module and can be removed safely by disabling "
+ "OpenChestsSilently in the config file. Please report this "
+ "error if you can reproduce it on an up-to-date server with only latest "
+ "ProtocolLib and latest Vanish-OG installed.");
suppressErrors = true;
}
}
}
}
private boolean isGameModeUpdate(PacketEvent event) {
// 1.19.3+: ClientboundPlayerInfoUpdatePacket exposes Set<Action>
try {
Set<EnumWrappers.PlayerInfoAction> actions = event.getPacket().getPlayerInfoActions().read(0);
if (actions != null)
return actions.contains(EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE);
} catch (FieldAccessException | IllegalArgumentException ignored) {
// legacy single-action packet on pre-1.19.3
}
try {
EnumWrappers.PlayerInfoAction action = event.getPacket().getPlayerInfoAction().read(0);
return action == EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE;
} catch (FieldAccessException | IllegalArgumentException ignored) {
return false;
}
}
private UUID extractUUID(PlayerInfoData infoData) {
UUID uuid = infoData.getProfileId();
if (uuid != null)
return uuid;
if (infoData.getProfile() != null)
return infoData.getProfile().getUUID();
return null;
}
}
@@ -14,154 +14,303 @@ import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.PlayerInfoData;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.google.common.collect.ImmutableList;
import com.comphenix.protocol.wrappers.WrappedRemoteChatSessionData;
import de.myzelyam.api.vanish.PlayerShowEvent;
import de.myzelyam.api.vanish.PostPlayerHideEvent;
import de.myzelyam.supervanish.SuperVanish;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import static com.comphenix.protocol.PacketType.Play.Server.PLAYER_INFO;
/**
* Marks visible vanished players as spectators in player info updates. On
* Purpur 1.19.4 this operates on the server-native
* ClientboundPlayerInfoUpdatePacket format and ViaSuite handles translation for
* connected 1.8-1.21.x clients.
*/
public class VanishIndication extends Feature {
private boolean suppressErrors = false;
public VanishIndication(SuperVanish plugin) {
super(plugin);
}
@Override
public boolean isActive() {
return plugin.getSettings().getBoolean("IndicationFeatures.MarkVanishedPlayersAsSpectators");
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVanish(PostPlayerHideEvent e) {
Player p = e.getPlayer();
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (!plugin.getVisibilityChanger().getHider().isHidden(p, onlinePlayer) && p != onlinePlayer) {
sendPlayerInfoChangeGameModePacket(onlinePlayer, p, true);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PlayerShowEvent e) {
final Player p = e.getPlayer();
for (final Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (!plugin.getVisibilityChanger().getHider().isHidden(p, onlinePlayer) && p != onlinePlayer) {
delay(() -> sendPlayerInfoChangeGameModePacket(onlinePlayer, p, false));
}
}
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
final Player p = e.getPlayer();
delay(() -> {
// tell others that p is a spectator
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (!plugin.getVisibilityChanger().getHider().isHidden(p, onlinePlayer)
&& p != onlinePlayer) {
if (!plugin.getVisibilityChanger().getHider().isHidden(p, onlinePlayer) && p != onlinePlayer) {
sendPlayerInfoChangeGameModePacket(onlinePlayer, p, true);
}
}
// tell p that others are spectators
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
if (!plugin.getVanishStateMgr().isVanished(onlinePlayer.getUniqueId())) continue;
if (!plugin.getVisibilityChanger().getHider().isHidden(onlinePlayer, p)
&& p != onlinePlayer) {
if (!plugin.getVanishStateMgr().isVanished(onlinePlayer.getUniqueId()))
continue;
if (!plugin.getVisibilityChanger().getHider().isHidden(onlinePlayer, p) && p != onlinePlayer) {
sendPlayerInfoChangeGameModePacket(p, onlinePlayer, true);
}
}
});
}
@Override
public void onEnable() {
ProtocolLibrary.getProtocolManager().addPacketListener(
new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO) {
new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO)
{
@Override
public void onPacketSending(PacketEvent event) {
try {
if (VanishIndication.this.plugin.getVanishStateMgr().getOnlineVanishedPlayers().isEmpty())
return;
// multiple events share same packet object
event.setPacket(event.getPacket().shallowClone());
List<PlayerInfoData> infoDataList = new ArrayList<>(
event.getPacket().getPlayerInfoDataLists().read(0));
Player receiver = event.getPlayer();
for (PlayerInfoData infoData : ImmutableList.copyOf(infoDataList)) {
boolean modified = false;
// Iterate a snapshot (ArrayList tolerates nulls; ImmutableList does not)
// so we can safely set() on infoDataList during the loop. ProtocolLib
// can hand back null entries during login packet flow on 1.19.4.
for (PlayerInfoData infoData : new ArrayList<>(infoDataList)) {
try {
if (!isGameModeUpdate(event))
break;
if (infoData == null)
continue;
if (extractUUID(infoData) == null)
continue;
if (!VanishIndication.this.plugin.getVisibilityChanger().getHider()
.isHidden(infoData.getProfile().getUUID(), receiver)
.isHidden(extractUUID(infoData), receiver)
&& VanishIndication.this.plugin.getVanishStateMgr()
.isVanished(infoData.getProfile().getUUID())) {
if (!receiver.getUniqueId().equals(infoData.getProfile().getUUID()))
.isVanished(extractUUID(infoData)))
{
if (!receiver.getUniqueId().equals(extractUUID(infoData)))
if (infoData.getGameMode() != EnumWrappers.NativeGameMode.SPECTATOR) {
int latency;
try {
latency = infoData.getLatency();
} catch (NoSuchMethodError e) {
latency = 21;
}
if (event.getPacket().getPlayerInfoAction().read(0)
!= EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE) {
continue;
}
PlayerInfoData newData = new PlayerInfoData(infoData.getProfile(),
latency, EnumWrappers.NativeGameMode.SPECTATOR,
infoData.getDisplayName());
infoDataList.remove(infoData);
infoDataList.add(newData);
PlayerInfoData newData = createGameModeUpdate(infoData,
EnumWrappers.NativeGameMode.SPECTATOR);
int index = infoDataList.indexOf(infoData);
infoDataList.set(index, newData);
modified = true;
}
}
} catch (UnsupportedOperationException ignored) {
}
}
event.getPacket().getPlayerInfoDataLists().write(0, infoDataList);
// Untouched packets must not be rewritten: writing back into
// ClientboundPlayerInfoUpdatePacket on 1.19.3+ also rewrites its
// final EnumSet<Action> field, which ProtocolLib cannot mutate.
if (modified)
event.getPacket().getPlayerInfoDataLists().write(0, infoDataList);
} catch (Exception | NoClassDefFoundError e) {
if (!suppressErrors) {
VanishIndication.this.plugin.logException(e);
plugin.getLogger().warning("IMPORTANT: Please make sure that you are using the latest " +
"dev-build of ProtocolLib and that your server is up-to-date! This error likely " +
"happened inside of ProtocolLib code which is out of SuperVanish's control. It's part " +
"of an optional feature module and can be removed safely by disabling " +
"MarkVanishedPlayersAsSpectators in the config file. Please report this " +
"error if you can reproduce it on an up-to-date server with only latest " +
"ProtocolLib and latest SV installed.");
plugin.getLogger().warning("IMPORTANT: Please make sure that you are using the latest "
+ "dev-build of ProtocolLib and that your server is up-to-date! This error likely "
+ "happened inside of ProtocolLib code which is out of Vanish-OG's control. It's part "
+ "of an optional feature module and can be removed safely by disabling "
+ "MarkVanishedPlayersAsSpectators in the config file. Please report this "
+ "error if you can reproduce it on an up-to-date server with only latest "
+ "ProtocolLib and latest Vanish-OG installed.");
suppressErrors = true;
}
}
}
});
}
private void sendPlayerInfoChangeGameModePacket(Player p, Player change, boolean spectator) {
PacketContainer packet = new PacketContainer(PLAYER_INFO);
packet.getPlayerInfoAction().write(0, EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE);
if (plugin.getVersionUtil().isOneDotXOrHigher(19)) {
packet.getPlayerInfoActions().write(0, EnumSet.of(EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE));
} else {
packet.getPlayerInfoAction().write(0, EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE);
}
List<PlayerInfoData> data = new ArrayList<>();
int ping = ThreadLocalRandom.current().nextInt(20) + 15;
data.add(new PlayerInfoData(WrappedGameProfile.fromPlayer(change), ping,
spectator ? EnumWrappers.NativeGameMode.SPECTATOR
: EnumWrappers.NativeGameMode.fromBukkit(change.getGameMode()),
WrappedChatComponent.fromText(change.getPlayerListName())));
EnumWrappers.NativeGameMode gameMode = spectator ? EnumWrappers.NativeGameMode.SPECTATOR
: EnumWrappers.NativeGameMode.fromBukkit(change.getGameMode());
WrappedChatComponent displayName = WrappedChatComponent
.fromText(LegacyComponentSerializer.legacySection().serialize(change.playerListName()));
WrappedGameProfile profile = WrappedGameProfile.fromPlayer(change);
if (plugin.getVersionUtil().isOneDotXOrHigher(19)) {
data.add(new PlayerInfoData(change.getUniqueId(), ping, true, gameMode, profile, displayName,
(WrappedRemoteChatSessionData) null));
} else {
data.add(new PlayerInfoData(profile, ping, gameMode, displayName));
}
packet.getPlayerInfoDataLists().write(0, data);
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(p, packet);
} catch (InvocationTargetException e) {
} catch (Exception e) {
throw new RuntimeException("Cannot send packet", e);
}
}
private boolean isGameModeUpdate(PacketEvent event) {
try {
Set<EnumWrappers.PlayerInfoAction> actions = event.getPacket().getPlayerInfoActions().read(0);
if (actions != null)
return actions.contains(EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE);
} catch (FieldAccessException | IllegalArgumentException ignored) {
// legacy single-action packet on pre-1.19.3
}
try {
EnumWrappers.PlayerInfoAction action = event.getPacket().getPlayerInfoAction().read(0);
return action == EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE;
} catch (FieldAccessException | IllegalArgumentException ignored) {
return false;
}
}
private UUID extractUUID(PlayerInfoData infoData) {
UUID uuid = infoData.getProfileId();
if (uuid != null)
return uuid;
if (infoData.getProfile() != null)
return infoData.getProfile().getUUID();
return null;
}
private PlayerInfoData createGameModeUpdate(PlayerInfoData infoData, EnumWrappers.NativeGameMode gameMode) {
UUID uuid = extractUUID(infoData);
if (plugin.getVersionUtil().isOneDotXOrHigher(19)) {
return new PlayerInfoData(uuid, infoData.getLatency(), infoData.isListed(), gameMode, infoData.getProfile(),
infoData.getDisplayName(), infoData.getRemoteChatSessionData());
}
return new PlayerInfoData(infoData.getProfile(), infoData.getLatency(), gameMode, infoData.getDisplayName());
}
}
@@ -26,44 +26,62 @@ import java.util.UUID;
public class CitizensHook extends PluginHook {
public CitizensHook(SuperVanish superVanish) {
super(superVanish);
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onNPCTarget(NPCSpeechEvent e) {
e.setCancelled(!checkContext(e.getContext()));
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onSpeechTargeted(SpeechEvent e) {
e.setCancelled(!checkContext(e.getContext()));
}
/**
* @return FALSE if the event should be cancelled, TRUE otherwise
*/
private boolean checkContext(SpeechContext context) {
// don't let it talk about hidden players
for (UUID uuid : superVanish.getVanishStateMgr().getOnlineVanishedPlayers()) {
if (context.getMessage().contains(Bukkit.getPlayer(uuid).getName())) {
return false;
}
}
// don't let hidden players receive it
Iterator<Talkable> iterator = context.iterator();
while (iterator.hasNext()) {
Talkable recipient = iterator.next();
Entity entity = recipient.getEntity();
if (!(entity instanceof Player))
continue;
Player player = (Player) entity;
if (superVanish.getVanishStateMgr().isVanished(player.getUniqueId())) {
iterator.remove();
}
}
// cancel contexts with only hidden recipients
return context.hasRecipients();
}
}
@@ -1,76 +0,0 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.hooks;
import de.myzelyam.api.vanish.PlayerHideEvent;
import de.myzelyam.api.vanish.PlayerShowEvent;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.dynmap.bukkit.DynmapPlugin;
public class DynmapHook extends PluginHook {
private final boolean sendJoinLeave;
private final SuperVanish superVanish;
public DynmapHook(SuperVanish superVanish) {
super(superVanish);
this.superVanish = superVanish;
sendJoinLeave
= superVanish.getSettings().getBoolean("HookOptions.DynmapSendJoinLeaveMessages")
&& !superVanish.getMessage("DynmapFakeJoin").equals("");
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVanish(PlayerHideEvent e) {
Player p = e.getPlayer();
DynmapPlugin dynmap = (DynmapPlugin) plugin;
dynmap.setPlayerVisiblity(p, false);
if (sendJoinLeave)
dynmap.sendBroadcastToWeb("",
superVanish.replacePlaceholders(superVanish.getMessage("DynmapFakeQuit"), p));
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PlayerShowEvent e) {
Player p = e.getPlayer();
DynmapPlugin dynmap = (DynmapPlugin) plugin;
dynmap.setPlayerVisiblity(p, true);
if (sendJoinLeave)
dynmap.sendBroadcastToWeb("",
superVanish.replacePlaceholders(superVanish.getMessage("DynmapFakeJoin"), p));
}
@EventHandler(priority = EventPriority.LOWEST)
public void onJoin(PlayerJoinEvent e) {
Player p = e.getPlayer();
DynmapPlugin dynmap = (DynmapPlugin) plugin;
if (superVanish.getVanishStateMgr().isVanished(p.getUniqueId())) {
dynmap.setPlayerVisiblity(p, false);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onQuit(PlayerQuitEvent e) {
Player p = e.getPlayer();
DynmapPlugin dynmap = (DynmapPlugin) plugin;
if (superVanish.getVanishStateMgr().isVanished(p.getUniqueId())) {
dynmap.setPlayerVisiblity(p, true);
}
}
}
@@ -37,87 +37,167 @@ public class EssentialsHook extends PluginHook {
@Override
public void run() {
try {
if (!Bukkit.getPluginManager().isPluginEnabled("Essentials")) return;
if (!Bukkit.getPluginManager().isPluginEnabled("Essentials"))
return;
for (UUID uuid : superVanish.getVanishStateMgr().getOnlineVanishedPlayers()) {
Player p = Bukkit.getPlayer(uuid);
User user = essentials.getUser(p);
if (user == null) continue;
if (user == null)
continue;
if (!user.isHidden())
user.setHidden(true);
}
} catch (Exception e) {
cancel();
superVanish.logException(e);
}
}
};
private BukkitTask forcedInvisibilityTask;
public EssentialsHook(SuperVanish superVanish) {
super(superVanish);
}
@Override
public void onPluginEnable(Plugin plugin) {
essentials = (Essentials) plugin;
forcedInvisibilityTask = forcedInvisibilityRunnable.runTaskTimer(superVanish, 0, 100);
forcedInvisibilityRunnable.run();
}
@Override
public void onPluginDisable(Plugin plugin) {
essentials = null;
forcedInvisibilityTask.cancel();
}
/**
* Essentials tracks its own vanish list in {@code getVanishedPlayersNew()} and
* re-hides its members from every new joiner via the deprecated
* {@code hidePlayer(Player)} API (see EssentialsPlayerListener#onPlayerJoin).
* That deprecated call parks a {@code null} plugin ref in CraftPlayer's
* invertedVisibilityEntities map, which Vanish-OG's plugin-scoped
* {@code showPlayer(Plugin, Player)} cannot clear. So {@code /sv cleanup} must
* drive Essentials' state back to "not vanished" on every online user — that's
* the only call that removes the entry from Essentials' list *and* fires the
* deprecated {@code showPlayer(Player)} that drops the null ref.
*/
@Override
public void onCleanup() {
if (essentials == null)
return;
for (Player online : Bukkit.getOnlinePlayers()) {
try {
User user = essentials.getUser(online);
if (user == null)
continue;
if (user.isVanished())
user.setVanished(false);
if (user.isHidden())
user.setHidden(false);
} catch (Exception e) {
superVanish.logException(e);
}
}
}
@EventHandler(priority = EventPriority.LOW)
public void onJoin(PlayerJoinEvent e) {
User user = essentials.getUser(e.getPlayer());
if (user == null) return;
if (user == null)
return;
if (superVanish.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId()) && !user.isHidden())
user.setHidden(true);
else user.setHidden(false);
else
user.setHidden(false);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVanish(PlayerHideEvent e) {
User user = essentials.getUser(e.getPlayer());
if (user == null) return;
if (user.isVanished()) user.setVanished(false);
if (user == null)
return;
if (user.isVanished())
user.setVanished(false);
preVanishHiddenPlayers.remove(e.getPlayer().getUniqueId());
user.setHidden(true);
}
@EventHandler
public void onReappear(PostPlayerShowEvent e) {
User user = essentials.getUser(e.getPlayer());
if (user == null) return;
if (user == null)
return;
user.setHidden(false);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onCommand(final PlayerCommandPreprocessEvent e) {
if (!CommandAction.VANISH_SELF.checkPermission(e.getPlayer(), superVanish)) return;
if (superVanish.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId())) return;
if (!CommandAction.VANISH_SELF.checkPermission(e.getPlayer(), superVanish))
return;
if (superVanish.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId()))
return;
String command = e.getMessage().toLowerCase(Locale.ENGLISH).split(" ")[0].replace("/", "")
.toLowerCase(Locale.ENGLISH);
if (command.split(":").length > 1) command = command.split(":")[1];
if (command.equals("supervanish") || command.equals("sv")
|| command.equals("v") || command.equals("vanish")) {
if (command.split(":").length > 1)
command = command.split(":")[1];
if (command.equals("supervanish") || command.equals("sv") || command.equals("v") || command.equals("vanish")) {
final User user = essentials.getUser(e.getPlayer());
if (user == null || !user.isAfk()) return;
if (user == null || !user.isAfk())
return;
user.setHidden(true);
preVanishHiddenPlayers.add(e.getPlayer().getUniqueId());
superVanish.getServer().getScheduler().runTaskLater(superVanish, new Runnable() {
@Override
public void run() {
if (preVanishHiddenPlayers.remove(e.getPlayer().getUniqueId())) {
user.setHidden(false);
}
}
}, 1);
}
}
}
@@ -10,14 +10,22 @@ package de.myzelyam.supervanish.hooks;
public class InvalidPluginHookException extends RuntimeException {
private static final long serialVersionUID = 1L;
public InvalidPluginHookException() {
}
public InvalidPluginHookException(String message) {
super(message);
}
public InvalidPluginHookException(Throwable cause) {
super(cause);
}
}
}
@@ -1,110 +0,0 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.hooks;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.UUID;
import be.maximvdw.placeholderapi.PlaceholderAPI;
import be.maximvdw.placeholderapi.PlaceholderReplaceEvent;
import be.maximvdw.placeholderapi.PlaceholderReplacer;
public class MVdWPlaceholderAPIHook extends PluginHook {
public MVdWPlaceholderAPIHook(SuperVanish superVanish) {
super(superVanish);
}
@Override
public void onPluginEnable(Plugin plugin) {
PlaceholderAPI.registerPlaceholder(superVanish, "supervanish_isvanished",
new PlaceholderReplacer() {
@Override
public String onPlaceholderReplace(PlaceholderReplaceEvent e) {
try {
Player p = e.getPlayer();
if (p == null) return "No";
try {
return superVanish.getVanishStateMgr().isVanished(p.getUniqueId()) ? "Yes"
: "No";
} catch (Exception er) {
superVanish.logException(er);
}
return null;
} catch (Throwable t) {
if (!(t instanceof NoClassDefFoundError || t instanceof
ConcurrentModificationException))
superVanish.logException(t);
return "No";
}
}
});
PlaceholderAPI.registerPlaceholder(superVanish, "supervanish_vanishedplayers",
new PlaceholderReplacer() {
@Override
public String onPlaceholderReplace(PlaceholderReplaceEvent e) {
try {
Player p = e.getPlayer();
Collection<UUID> onlineVanishedPlayers = superVanish.getVanishStateMgr()
.getOnlineVanishedPlayers();
String playerListMessage = "";
for (UUID uuid : onlineVanishedPlayers) {
Player onlineVanished = Bukkit.getPlayer(uuid);
if (onlineVanished == null) continue;
if (p != null && superVanish.getSettings().getBoolean(
"IndicationFeatures.LayeredPermissions.HideInvisibleInCommands", false)
&& !superVanish.hasPermissionToSee(p, onlineVanished)) {
continue;
}
playerListMessage = playerListMessage + onlineVanished.getName() + ", ";
}
return playerListMessage.length() > 3
? playerListMessage.substring(0, playerListMessage.length() - 2)
: playerListMessage;
} catch (Throwable t) {
if (!(t instanceof NoClassDefFoundError || t instanceof
ConcurrentModificationException))
superVanish.logException(t);
return "";
}
}
});
PlaceholderAPI.registerPlaceholder(superVanish, "supervanish_playercount",
new PlaceholderReplacer() {
@Override
public String onPlaceholderReplace(PlaceholderReplaceEvent e) {
try {
Player p = e.getPlayer();
int playercount = Bukkit.getOnlinePlayers().size();
for (UUID uuid : superVanish.getVanishStateMgr()
.getOnlineVanishedPlayers()) {
Player onlineVanished = Bukkit.getPlayer(uuid);
if (onlineVanished == null) continue;
if (p == null || !superVanish.canSee(p, onlineVanished))
playercount--;
}
return playercount + "";
} catch (Throwable t) {
if (!(t instanceof NoClassDefFoundError || t instanceof
ConcurrentModificationException))
superVanish.logException(t);
return Bukkit.getOnlinePlayers().size() + "";
}
}
});
}
}
@@ -0,0 +1,152 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.hooks;
import de.myzelyam.supervanish.SuperVanish;
import io.github.miniplaceholders.api.Expansion;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.Collection;
import java.util.UUID;
public class MiniPlaceholdersHook extends PluginHook {
private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacyAmpersand();
private final String yes, no, prefix, suffix;
private Expansion expansion;
public MiniPlaceholdersHook(SuperVanish superVanish) {
super(superVanish);
yes = superVanish.getMessage("PlaceholderIsVanishedYes");
no = superVanish.getMessage("PlaceholderIsVanishedNo");
prefix = superVanish.getMessage("PlaceholderVanishPrefix");
suffix = superVanish.getMessage("PlaceholderVanishSuffix");
}
@Override
public void onPluginEnable(Plugin plugin) {
expansion = Expansion.builder("supervanish")
.audiencePlaceholder("isvanished", (audience, queue, ctx) -> textTag(isVanishedText(audience)))
.audiencePlaceholder("vanishprefix",
(audience, queue, ctx) -> componentTag(isVanished(audience) ? prefix : ""))
.audiencePlaceholder("vanishsuffix",
(audience, queue, ctx) -> componentTag(isVanished(audience) ? suffix : ""))
.audiencePlaceholder("vanishedplayers", (audience, queue, ctx) -> textTag(getVanishedPlayers(audience)))
.audiencePlaceholder("playercount",
(audience, queue, ctx) -> textTag(String.valueOf(getPlayerCount(audience))))
.build();
expansion.register();
}
@Override
public void onPluginDisable(Plugin plugin) {
if (expansion != null && expansion.registered()) {
expansion.unregister();
}
expansion = null;
}
private String isVanishedText(Object audience) {
return isVanished(audience) ? yes : no;
}
private boolean isVanished(Object audience) {
if (!(audience instanceof Player))
return false;
return superVanish.getVanishStateMgr().isVanished(((Player) audience).getUniqueId());
}
private String getVanishedPlayers(Object audience) {
Player viewer = audience instanceof Player ? (Player) audience : null;
Collection<UUID> onlineVanishedPlayers = superVanish.getVanishStateMgr().getOnlineVanishedPlayers();
StringBuilder playerListMessage = new StringBuilder();
for (UUID uuid : onlineVanishedPlayers) {
Player onlineVanished = Bukkit.getPlayer(uuid);
if (onlineVanished == null)
continue;
if (viewer != null
&& superVanish.getSettings()
.getBoolean("IndicationFeatures.LayeredPermissions.HideInvisibleInCommands", false)
&& !superVanish.hasPermissionToSee(viewer, onlineVanished))
{
continue;
}
if (playerListMessage.length() > 0) {
playerListMessage.append(", ");
}
playerListMessage.append(onlineVanished.getName());
}
return playerListMessage.toString();
}
private int getPlayerCount(Object audience) {
Player viewer = audience instanceof Player ? (Player) audience : null;
int playerCount = Bukkit.getOnlinePlayers().size();
for (UUID uuid : superVanish.getVanishStateMgr().getOnlineVanishedPlayers()) {
Player onlineVanished = Bukkit.getPlayer(uuid);
if (onlineVanished == null)
continue;
if (viewer == null || !superVanish.canSee(viewer, onlineVanished)) {
playerCount--;
}
}
return playerCount;
}
private Tag textTag(String value) {
return Tag.selfClosingInserting(Component.text(value));
}
private Tag componentTag(String value) {
return Tag.selfClosingInserting(LEGACY_SERIALIZER.deserialize(value));
}
}
@@ -0,0 +1,202 @@
package de.myzelyam.supervanish.hooks;
import de.myzelyam.api.vanish.PlayerShowEvent;
import de.myzelyam.api.vanish.PostPlayerHideEvent;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class OpenInvHook extends PluginHook {
private boolean errorLogged = false;
private final Set<UUID> alreadyHiddenBeforeVanishing = new HashSet<>();
public OpenInvHook(SuperVanish superVanish) {
super(superVanish);
}
@EventHandler
public void onVanish(PostPlayerHideEvent e) {
try {
Player p = e.getPlayer();
if (getSilentContainerStatus(p)) {
alreadyHiddenBeforeVanishing.add(p.getUniqueId());
} else {
if (!p.hasPermission("sv.silentchest"))
return;
setSilentContainerStatus(p, true);
}
} catch (Exception | NoSuchMethodError | NoClassDefFoundError er) {
if (!errorLogged) {
superVanish.logException(er);
errorLogged = true;
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PlayerShowEvent e) {
try {
Player p = e.getPlayer();
if (!alreadyHiddenBeforeVanishing.remove(p.getUniqueId())) {
setSilentContainerStatus(p, false);
}
} catch (Exception | NoSuchMethodError | NoClassDefFoundError er) {
if (!errorLogged) {
superVanish.logException(er);
errorLogged = true;
}
}
}
@EventHandler(priority = EventPriority.LOW)
public void onJoin(PlayerJoinEvent e) {
try {
Player p = e.getPlayer();
if (superVanish.getVanishStateMgr().isVanished(p.getUniqueId())) {
if (getSilentContainerStatus(p)) {
alreadyHiddenBeforeVanishing.add(p.getUniqueId());
} else {
if (!p.hasPermission("sv.silentchest"))
return;
setSilentContainerStatus(p, true);
}
}
} catch (Exception | NoSuchMethodError | NoClassDefFoundError er) {
if (!errorLogged) {
superVanish.logException(er);
errorLogged = true;
}
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onQuit(PlayerQuitEvent e) {
try {
Player p = e.getPlayer();
if (superVanish.getVanishStateMgr().isVanished(p.getUniqueId())) {
if (!alreadyHiddenBeforeVanishing.remove(p.getUniqueId())) {
setSilentContainerStatus(p, false);
}
}
} catch (Exception | NoSuchMethodError | NoClassDefFoundError er) {
if (!errorLogged) {
superVanish.logException(er);
errorLogged = true;
}
}
}
public boolean openPlayerInventory(Player vanished, Player target) {
try {
// OpenInv 4.2.0+: openInventory's second arg is ISpecialInventory,
// not org.bukkit.inventory.Inventory. The interface isn't on our
// compile classpath, so resolve it reflectively.
Class<?> iSpecialInventory = Class.forName("com.lishid.openinv.internal.ISpecialInventory");
Method getSpecialInventoryMethod = plugin.getClass().getMethod("getSpecialInventory", Player.class,
boolean.class);
Object specialInventory = getSpecialInventoryMethod.invoke(plugin, target, true);
Method openInventoryMethod = plugin.getClass().getMethod("openInventory", Player.class, iSpecialInventory);
openInventoryMethod.invoke(plugin, vanished, specialInventory);
} catch (Exception | NoSuchMethodError | NoClassDefFoundError e) {
if (!errorLogged) {
superVanish.logException(e);
errorLogged = true;
}
return false;
}
return true;
}
// OpenInv 4.2.0+ signatures take OfflinePlayer, not Player. Player extends
// OfflinePlayer so the argument is compatible; only the reflected lookup
// signature needed updating.
private boolean getSilentContainerStatus(Player player) throws ReflectiveOperationException {
Method method = plugin.getClass().getMethod("getSilentContainerStatus", OfflinePlayer.class);
return (Boolean) method.invoke(plugin, player);
}
private void setSilentContainerStatus(Player player, boolean status) throws ReflectiveOperationException {
Method method = plugin.getClass().getMethod("setSilentContainerStatus", OfflinePlayer.class, boolean.class);
method.invoke(plugin, player, status);
}
}
@@ -1,112 +0,0 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.hooks;
import de.myzelyam.supervanish.SuperVanish;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.UUID;
public class PlaceholderAPIHook extends PluginHook {
public PlaceholderAPIHook(SuperVanish superVanish) {
super(superVanish);
new SVPlaceholderExpansion().register();
}
public static String translatePlaceholders(String msg, Player p) {
return PlaceholderAPI.setPlaceholders((OfflinePlayer) p, msg);
}
public class SVPlaceholderExpansion extends PlaceholderExpansion {
@Override
public boolean persist() {
return true;
}
@Override
public boolean canRegister() {
return true;
}
@Override
public String getAuthor() {
return superVanish.getDescription().getAuthors().toString();
}
@Override
public String getIdentifier() {
return "supervanish";
}
@Override
public String getVersion() {
return superVanish.getDescription().getVersion();
}
@Override
public String onRequest(OfflinePlayer op, String id) {
try {
Player p;
if (op instanceof Player)
p = (Player) op;
else
p = null;
if (id.equalsIgnoreCase("isvanished")
|| id.equalsIgnoreCase("isinvisible")
|| id.equalsIgnoreCase("vanished")
|| id.equalsIgnoreCase("invisible"))
return p != null && superVanish.getVanishStateMgr().isVanished(p.getUniqueId())
? "Yes" : "No";
if (id.equalsIgnoreCase("onlinevanishedplayers")
|| id.equalsIgnoreCase("onlinevanished")
|| id.equalsIgnoreCase("invisibleplayers")
|| id.equalsIgnoreCase("vanishedplayers")
|| id.equalsIgnoreCase("hiddenplayers")) {
Collection<UUID> onlineVanishedPlayers = superVanish.getVanishStateMgr()
.getOnlineVanishedPlayers();
String playerListMessage = "";
for (UUID uuid : onlineVanishedPlayers) {
Player onlineVanished = Bukkit.getPlayer(uuid);
if (onlineVanished == null) continue;
if (superVanish.getSettings().getBoolean(
"IndicationFeatures.LayeredPermissions.HideInvisibleInCommands", false)
&& !superVanish.hasPermissionToSee(p, onlineVanished)) {
continue;
}
playerListMessage = playerListMessage + onlineVanished.getName() + ", ";
}
return playerListMessage.length() > 3
? playerListMessage.substring(0, playerListMessage.length() - 2)
: playerListMessage;
}
if (id.equalsIgnoreCase("playercount")
|| id.equalsIgnoreCase("onlineplayers")) {
int playercount = Bukkit.getOnlinePlayers().size();
for (UUID uuid : superVanish.getVanishStateMgr()
.getOnlineVanishedPlayers()) {
Player onlineVanished = Bukkit.getPlayer(uuid);
if (onlineVanished == null) continue;
if (p == null || !superVanish.canSee(p, onlineVanished)) playercount--;
}
return playercount + "";
}
} catch (Exception e) {
superVanish.logException(e);
}
return null;
}
}
}
@@ -14,8 +14,8 @@ import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
/**
* Represents a hook into a plugin to support its functionality or make it support SuperVanish's
* functionality
* Represents a hook into a plugin to support its functionality or make it
* support SuperVanish's functionality
*/
public abstract class PluginHook implements Listener {
@@ -23,20 +23,39 @@ public abstract class PluginHook implements Listener {
protected Plugin plugin;
public PluginHook(SuperVanish superVanish) {
this.superVanish = superVanish;
}
public void onPluginEnable(Plugin plugin) {
}
public void onPluginDisable(Plugin plugin) {
}
/**
* Called by {@code /sv cleanup} so hooks can drop any hide state they are
* responsible for. Default is a no-op — hooks that keep their own vanish
* tracking (Essentials' {@code getVanishedPlayersNew} + deprecated
* {@code hidePlayer(Player)} calls) override this to reset it.
*/
public void onCleanup() {
}
public Plugin getPlugin() {
return plugin;
}
void setPlugin(Plugin plugin) {
this.plugin = plugin;
}
}
@@ -25,89 +25,176 @@ import java.util.logging.Level;
public class PluginHookMgr implements Listener {
private static final Map<String, Class<? extends PluginHook>> REGISTERED_HOOKS
= new HashMap<String, Class<? extends PluginHook>>() {{
put("Essentials", EssentialsHook.class);
put("Citizens", CitizensHook.class);
put("PlaceholderAPI", PlaceholderAPIHook.class);
put("dynmap", DynmapHook.class);
put("SuperTrails", SuperTrailsHook.class);
put("TrailGUI", TrailGUIHook.class);
put("MVdWPlaceholderAPI", MVdWPlaceholderAPIHook.class);
}};
private static final Map<String, Class<? extends PluginHook>> REGISTERED_HOOKS = new HashMap<String, Class<? extends PluginHook>>() {
{
put("Essentials", EssentialsHook.class);
put("Citizens", CitizensHook.class);
put("Utilities-OG", MiniPlaceholdersHook.class);
put("TrailGUI", TrailGUIHook.class);
put("OpenInv", OpenInvHook.class);
put("TAB-OG", TabOGHook.class);
}
};
private final SuperVanish plugin;
private Set<PluginHook> activeHooks = new HashSet<>();
public PluginHookMgr(SuperVanish plugin) {
this.plugin = plugin;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
for (Plugin alreadyEnabledPlugin : Bukkit.getPluginManager().getPlugins())
if (alreadyEnabledPlugin.isEnabled())
onPluginEnable(new PluginEnableEvent(alreadyEnabledPlugin));
}
@EventHandler
public void onPluginEnable(PluginEnableEvent e) {
Plugin plugin = e.getPlugin();
if (REGISTERED_HOOKS.get(plugin.getName()) == null) return;
if (isHookDisabled(plugin.getName())) return;
if (REGISTERED_HOOKS.get(plugin.getName()) == null)
return;
if (isHookDisabled(plugin.getName()))
return;
PluginHook hook = null;
try {
hook = REGISTERED_HOOKS.get(plugin.getName()).getConstructor(SuperVanish.class).
newInstance(PluginHookMgr.this.plugin);
hook = REGISTERED_HOOKS.get(plugin.getName()).getConstructor(SuperVanish.class)
.newInstance(PluginHookMgr.this.plugin);
hook.setPlugin(plugin);
hook.onPluginEnable(plugin);
Bukkit.getPluginManager().registerEvents(hook, plugin);
activeHooks.add(hook);
PluginHookMgr.this.plugin.log(
Level.INFO, "Hooked into " + plugin.getName());
PluginHookMgr.this.plugin.log(Level.INFO, "Hooked into " + plugin.getName());
} catch (NoClassDefFoundError er) {
Bukkit.getLogger().warning("NoClassDefFoundError for SV-Hook(v"
+ this.plugin.getDescription().getVersion() + ") "
+ (hook != null ? hook.getClass().getSimpleName() : "?") + " of plugin "
+ plugin.getName() + " v" + plugin.getDescription().getVersion()
+ ", please report this if you are using the latest version of that" +
" plugin!");
Bukkit.getLogger()
.warning("NoClassDefFoundError for SV-Hook(v" + this.plugin.getPluginMeta().getVersion() + ") "
+ (hook != null ? hook.getClass().getSimpleName() : "?") + " of plugin " + plugin.getName()
+ " v" + plugin.getPluginMeta().getVersion()
+ ", please report this if you are using the latest version of that" + " plugin!");
} catch (Exception er) {
if (er.getMessage() != null
&& er.getMessage().contains("Unable to find handler list for event")) {
this.plugin.log(Level.WARNING, "" + er.getMessage()
+ "; This is not an issue with SuperVanish");
if (er.getMessage() != null && er.getMessage().contains("Unable to find handler list for event")) {
this.plugin.log(Level.WARNING, "" + er.getMessage() + "; This is not an issue with Vanish-OG");
return;
} else if (er.getCause() != null && er.getCause().getMessage() != null && er.getCause()
.getMessage().contains("Unable to find handler list for event ")) {
this.plugin.log(Level.WARNING, "" + er.getCause()
.getMessage() + "; This is not an issue with SuperVanish");
} else if (er.getCause() != null && er.getCause().getMessage() != null
&& er.getCause().getMessage().contains("Unable to find handler list for event "))
{
this.plugin.log(Level.WARNING,
"" + er.getCause().getMessage() + "; This is not an issue with Vanish-OG");
return;
}
this.plugin.logException(new InvalidPluginHookException(er));
this.plugin.log(Level.WARNING, "Affected by this error is only the "
+ plugin.getName() + "-Hook, all other hooks and features aren't affected.");
this.plugin.log(Level.WARNING, "Affected by this error is only the " + plugin.getName()
+ "-Hook, all other hooks and features aren't affected.");
}
}
private boolean isHookDisabled(String pluginName) {
if (pluginName.equalsIgnoreCase("dynmap"))
return !plugin.getSettings().getBoolean("HookOptions.EnableDynmapHook");
if (pluginName.equalsIgnoreCase("Utilities-OG"))
return !plugin.getSettings().getBoolean("HookOptions.EnableUtilitiesOGHook", true);
if (pluginName.equalsIgnoreCase("TAB-OG"))
return !plugin.getSettings().getBoolean("HookOptions.EnableTabOGHook", true);
return !plugin.getSettings().getBoolean("HookOptions.Enable" + pluginName + "Hook", true);
}
@EventHandler
public void onPluginDisable(PluginDisableEvent e) {
Plugin plugin = e.getPlugin();
PluginHook hook = getActiveHook(plugin);
if (hook == null) return;
if (hook == null)
return;
try {
hook.onPluginDisable(plugin);
} catch (Exception e1) {
this.plugin.logException(new InvalidPluginHookException(e1));
}
hook.setPlugin(null);
activeHooks.remove(hook);
}
private PluginHook getActiveHook(Plugin plugin) {
for (PluginHook hook : activeHooks) if (hook.getPlugin() == plugin) return hook;
for (PluginHook hook : activeHooks)
if (hook.getPlugin() == plugin)
return hook;
return null;
}
public boolean isHookActive(Class<? extends PluginHook> hookClass) {
for (PluginHook hook : activeHooks) {
if (hook.getClass().equals(hookClass)) {
return true;
}
}
return false;
}
// Must run before the rest of the plugin tears down so TAB-OG's static
// HANDLERS list doesn't keep a reference to a disabled SuperVanish.
public void onSuperVanishDisable() {
for (PluginHook hook : activeHooks) {
if (hook instanceof TabOGHook) {
((TabOGHook) hook).onSuperVanishDisable();
}
}
}
public void onCleanup() {
for (PluginHook hook : activeHooks) {
try {
hook.onCleanup();
} catch (Exception e) {
plugin.logException(e);
}
}
}
}
@@ -1,61 +0,0 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.hooks;
import de.myzelyam.api.vanish.PlayerHideEvent;
import de.myzelyam.api.vanish.PlayerShowEvent;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import me.kvq.plugin.trails.API.SuperTrailsAPI;
public class SuperTrailsHook extends PluginHook {
public SuperTrailsHook(SuperVanish superVanish) {
super(superVanish);
}
@Override
public void onPluginEnable(Plugin plugin) {
for (Player p : Bukkit.getOnlinePlayers()) {
if (superVanish.getVanishStateMgr().isVanished(p.getUniqueId())) {
SuperTrailsAPI.HideTrailFor(p, true);
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVanish(PlayerHideEvent e) {
SuperTrailsAPI.HideTrailFor(e.getPlayer(), true);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PlayerShowEvent e) {
SuperTrailsAPI.HideTrailFor(e.getPlayer(), false);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onJoin(PlayerJoinEvent e) {
if (!superVanish.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId())) return;
SuperTrailsAPI.HideTrailFor(e.getPlayer(), true);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onQuit(PlayerQuitEvent e) {
if (!superVanish.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId())) return;
SuperTrailsAPI.HideTrailFor(e.getPlayer(), false);
}
}
@@ -0,0 +1,214 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.hooks;
import de.myzelyam.api.vanish.PostPlayerHideEvent;
import de.myzelyam.api.vanish.PostPlayerShowEvent;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.visibility.VanishStateMgr;
import me.neznamy.tab.api.TabPlayer;
import me.neznamy.tab.api.integration.VanishIntegration;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Method;
import java.util.UUID;
public class TabOGHook extends PluginHook {
private VanishOGIntegration integration;
public TabOGHook(SuperVanish superVanish) {
super(superVanish);
}
@Override
public void onPluginEnable(Plugin plugin) {
// Do not double-register if an earlier lifecycle already registered one.
unregisterIfPresent();
integration = new VanishOGIntegration(superVanish);
integration.register();
}
@Override
public void onPluginDisable(Plugin plugin) {
unregisterIfPresent();
}
// Called from SuperVanish.onDisable() so the integration is removed from
// TAB-OG's static HANDLERS list before the plugin's state is torn down.
// Without this, TAB-OG keeps a stale handler whose plugin reference no
// longer has valid state during subsequent logins.
public void onSuperVanishDisable() {
unregisterIfPresent();
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVanish(PostPlayerHideEvent event) {
notifyTabFeatures(event.getPlayer().getUniqueId());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onReappear(PostPlayerShowEvent event) {
notifyTabFeatures(event.getPlayer().getUniqueId());
}
private void unregisterIfPresent() {
if (integration != null) {
try {
integration.unregister();
} catch (Throwable ignored) {
// TAB-OG may already be unloaded; removing a missing handler is harmless.
}
integration = null;
}
}
private void notifyTabFeatures(UUID playerUuid) {
// Fire once immediately for metadata-based TAB-OG features and once after
// BackendTabPlayer's vanish cache window so cache-backed features refresh too.
Bukkit.getScheduler().runTask(superVanish, () -> notifyTabFeaturesNow(playerUuid));
Bukkit.getScheduler().runTaskLater(superVanish, () -> notifyTabFeaturesNow(playerUuid), 20L);
}
private void notifyTabFeaturesNow(UUID playerUuid) {
if (integration == null) {
return;
}
try {
Class<?> tabClass = Class.forName("me.neznamy.tab.shared.TAB");
Object tab = tabClass.getMethod("getInstance").invoke(null);
if (tab == null) {
return;
}
Object tabPlayer = tabClass.getMethod("getPlayer", UUID.class).invoke(tab, playerUuid);
if (tabPlayer == null) {
return;
}
Object featureManager = tabClass.getMethod("getFeatureManager").invoke(tab);
Class<?> tabPlayerClass = Class.forName("me.neznamy.tab.shared.platform.TabPlayer");
Method vanishChangeMethod = featureManager.getClass().getMethod("onVanishStatusChange", tabPlayerClass);
vanishChangeMethod.invoke(featureManager, tabPlayer);
} catch (ReflectiveOperationException ignored) {
// TAB-OG implementation internals are optional and may differ across versions.
} catch (Throwable t) {
superVanish.logException(t);
}
}
private static final class VanishOGIntegration extends VanishIntegration {
private final SuperVanish plugin;
private VanishOGIntegration(SuperVanish plugin) {
super("Vanish-OG");
this.plugin = plugin;
}
// TAB-OG invokes this on its async CPU-manager thread during join
// processing, so every field access must tolerate partial-enable and
// partial-disable states. Any exception thrown here propagates through
// TAB-OG's feature pipeline and breaks player login packet flow.
@Override
public boolean canSee(@NotNull TabPlayer viewer, @NotNull TabPlayer target) {
try {
final VanishStateMgr stateMgr = plugin.getVanishStateMgr();
if (stateMgr == null)
return true;
if (!stateMgr.isVanished(target.getUniqueId()))
return true;
final Player bukkitViewer = Bukkit.getPlayer(viewer.getUniqueId());
if (bukkitViewer == null)
return true;
// Direct permission check only: plugin.hasPermissionToSee() reaches
// LayeredPermissionChecker, which iterates the non-thread-safe
// vanishPlayers HashSet on SuperVanish. That's safe on the Bukkit
// main thread but not here, so we stick to Player.hasPermission.
return bukkitViewer.hasPermission("sv.see");
} catch (Throwable t) {
plugin.logException(t);
return true;
}
}
@Override
public boolean isVanished(@NotNull TabPlayer player) {
try {
final VanishStateMgr stateMgr = plugin.getVanishStateMgr();
if (stateMgr == null)
return false;
return stateMgr.isVanished(player.getUniqueId());
} catch (Throwable t) {
plugin.logException(t);
return false;
}
}
}
}
@@ -23,28 +23,37 @@ import ca.jamiesinn.trailgui.TrailGUI;
public class TrailGUIHook extends PluginHook {
public TrailGUIHook(SuperVanish superVanish) {
super(superVanish);
}
@Override
public void onPluginEnable(Plugin plugin) {
if (!(plugin instanceof TrailGUI)) {
superVanish.log(Level.WARNING,
"Failed to hook into TrailGUI. (PluginNotFound)");
superVanish.log(Level.WARNING, "Failed to hook into TrailGUI. (PluginNotFound)");
return;
}
PlayerMoveEvent.getHandlerList().unregister(plugin);
final Listeners trailGUIListeners = new Listeners((TrailGUI) plugin);
plugin.getServer().getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if (superVanish.getVanishStateMgr()
.getOnlineVanishedPlayers().contains(
event.getPlayer().getUniqueId()))
if (superVanish.getVanishStateMgr().getOnlineVanishedPlayers()
.contains(event.getPlayer().getUniqueId()))
return;
trailGUIListeners.onPlayerMove(event);
}
}, plugin);
}
}
@@ -10,7 +10,6 @@ package de.myzelyam.supervanish.listeners;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.VanishPlayer;
import de.myzelyam.supervanish.features.Broadcast;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -19,8 +18,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.entity.*;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
public class GeneralListener implements Listener {
@@ -29,110 +26,158 @@ public class GeneralListener implements Listener {
private final FileConfiguration config;
public GeneralListener(SuperVanish plugin) {
this.plugin = plugin;
config = plugin.getSettings();
}
@EventHandler(priority = EventPriority.HIGH)
public void onDamage(EntityDamageByEntityEvent e) {
try {
if (!(e.getDamager() instanceof Player)) return;
if (e.getEntity() == null) return;
if (!(e.getDamager() instanceof Player))
return;
if (e.getEntity() == null)
return;
Player p = (Player) e.getDamager();
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
if (config.getBoolean("RestrictiveOptions.PreventHittingEntities")
&& !p.hasPermission("sv.damageentities") && !p.hasPermission("sv.damage")) {
&& !p.hasPermission("sv.damageentities") && !p.hasPermission("sv.damage"))
{
plugin.sendMessage(p, "EntityHitDenied", p);
e.setCancelled(true);
}
}
} catch (Exception er) {
plugin.logException(er);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerDeath(PlayerDeathEvent e) {
try {
Player p = e.getEntity();
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
String deathMessage = e.getDeathMessage();
e.setDeathMessage(null);
if (deathMessage != null)
Broadcast.announceSilentDeath(p, plugin, deathMessage);
}
}
} catch (Exception er) {
plugin.logException(er);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onFoodLevelChange(FoodLevelChangeEvent e) {
try {
if (e.getEntity() instanceof Player && config.getBoolean("InvisibilityFeatures.DisableHunger")) {
Player p = (Player) e.getEntity();
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId())
&& e.getFoodLevel() <= p.getFoodLevel())
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId()) && e.getFoodLevel() <= p.getFoodLevel())
e.setCancelled(true);
}
} catch (Exception er) {
plugin.logException(er);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onDamage(EntityDamageEvent e) {
try {
if (!(e.getEntity() instanceof Player)) return;
if (!(e.getEntity() instanceof Player))
return;
Player p = (Player) e.getEntity();
if (!config.getBoolean("InvisibilityFeatures.DisableDamage")) return;
if (!config.getBoolean("InvisibilityFeatures.DisableDamage"))
return;
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
e.setCancelled(true);
}
} catch (Exception er) {
plugin.logException(er);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onTarget(EntityTargetEvent e) {
try {
if (!(e.getTarget() instanceof Player)) return;
if (!config.getBoolean("InvisibilityFeatures.DisableMobTarget")) return;
if (!(e.getTarget() instanceof Player))
return;
if (!config.getBoolean("InvisibilityFeatures.DisableMobTarget"))
return;
Player p = (Player) e.getTarget();
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
e.setCancelled(true);
}
} catch (Exception er) {
plugin.logException(er);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onItemPickUp(PlayerPickupItemEvent e) {
public void onItemPickUp(EntityPickupItemEvent e) {
try {
VanishPlayer vanishPlayer = plugin.getVanishPlayer(e.getPlayer());
if (vanishPlayer == null || !vanishPlayer.isOnlineVanished()) return;
if (!(e.getEntity() instanceof Player player))
return;
VanishPlayer vanishPlayer = plugin.getVanishPlayer(player);
if (vanishPlayer == null || !vanishPlayer.isOnlineVanished())
return;
if (!vanishPlayer.hasItemPickUpsEnabled())
e.setCancelled(true);
if (plugin.getSettings().getBoolean("RestrictiveOptions.PreventModifyingOwnInventory")
&& !vanishPlayer.getPlayer().hasPermission("sv.modifyowninv")) {
&& !player.hasPermission("sv.modifyowninv"))
{
e.setCancelled(true);
}
} catch (Exception er) {
plugin.logException(er);
}
}
@EventHandler
public void onPlayerCropTrample(PlayerInteractEvent e) {
try {
if (!plugin.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId())) return;
if (e.getAction() != Action.PHYSICAL) return;
if (!plugin.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId()))
return;
if (e.getAction() != Action.PHYSICAL)
return;
if (e.getClickedBlock() != null && e.getClickedBlock().getType().toString().matches("SOIL|FARMLAND"))
e.setCancelled(true);
} catch (Exception er) {
plugin.logException(er);
}
}
}
@@ -9,9 +9,7 @@
package de.myzelyam.supervanish.listeners;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.features.Broadcast;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
@@ -25,79 +23,101 @@ public class JoinListener implements EventExecutor, Listener {
private final SuperVanish plugin;
public JoinListener(SuperVanish plugin) {
this.plugin = plugin;
}
@Override
public void execute(Listener l, Event event) {
try {
if (event instanceof PlayerJoinEvent) {
PlayerJoinEvent e = (PlayerJoinEvent) event;
final Player p = e.getPlayer();
// vanished:
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
// hide self
for (Player onlinePlayer : Bukkit.getOnlinePlayers())
if (!plugin.hasPermissionToSee(onlinePlayer, p))
plugin.getVisibilityChanger().getHider().setHidden(p, onlinePlayer, true);
// Join message
if (plugin.getSettings().getBoolean("MessageOptions.HideRealJoinQuitMessages")) {
e.setJoinMessage(null);
Broadcast.announceSilentJoin(p, plugin);
}
// collision
try {
//noinspection deprecation
p.spigot().setCollidesWithEntities(false);
} catch (NoClassDefFoundError | NoSuchMethodError ignored) {
}
// reminding message
if (plugin.getSettings().getBoolean("MessageOptions.RemindVanishedOnJoin")) {
plugin.sendMessage(p, "RemindingMessage", p);
}
// re-add action bar
if (plugin.getActionBarMgr() != null && plugin.getSettings().getBoolean(
"MessageOptions.DisplayActionBar")) {
if (plugin.getActionBarMgr() != null
&& plugin.getSettings().getBoolean("MessageOptions.DisplayActionBar"))
{
plugin.getActionBarMgr().addActionBar(p);
}
// sleep state
p.setSleepingIgnored(true);
// adjust fly
if (plugin.getSettings().getBoolean("InvisibilityFeatures.Fly.Enable")) {
p.setAllowFlight(true);
}
// metadata
p.setMetadata("vanished", new FixedMetadataValue(plugin, true));
} else {
// not vanished:
// metadata
p.removeMetadata("vanished", plugin);
}
new BukkitRunnable() {
@Override
public void run() {
plugin.reconcileVisibility(p);
}
}.runTaskLater(plugin, 1L);
// not necessarily vanished:
// recreate files msg
if ((p.hasPermission("sv.recreatecfg") || p.hasPermission("sv.recreatefiles"))
&& (plugin.getConfigMgr().isSettingsUpdateRequired()
|| plugin.getConfigMgr().isMessagesUpdateRequired())) {
String currentVersion = plugin.getDescription().getVersion();
boolean isDismissed =
plugin.getPlayerData().getBoolean("PlayerData." + p.getUniqueId() + ".dismissed."
+ currentVersion.replace(".", "_"), false);
&& plugin.getConfigMgr().isMessagesUpdateRequired())
{
String currentVersion = plugin.getPluginMeta().getVersion();
boolean isDismissed = plugin.getVanishStateMgr().isDismissed(p.getUniqueId().toString(),
currentVersion);
if (!isDismissed)
new BukkitRunnable() {
@Override
public void run() {
plugin.sendMessage(p, "RecreationRequiredMsg", p);
}
}.runTaskLater(plugin, 1);
}
// hide others
for (Player onlinePlayer : Bukkit.getOnlinePlayers())
if (plugin.getVanishStateMgr().isVanished(onlinePlayer.getUniqueId())
&& !plugin.hasPermissionToSee(p, onlinePlayer))
plugin.getVisibilityChanger().getHider().setHidden(onlinePlayer, p, true);
}
} catch (Exception er) {
plugin.logException(er);
}
}
}
}
@@ -11,55 +11,65 @@ package de.myzelyam.supervanish.listeners;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.commands.CommandAction;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.metadata.FixedMetadataValue;
public class LoginListener implements Listener {
private final SuperVanish plugin;
public LoginListener(SuperVanish plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onLogin(PlayerLoginEvent e) {
try {
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) return;
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED)
return;
final Player p = e.getPlayer();
boolean vanished = plugin.getVanishStateMgr().isVanished(p.getUniqueId());
boolean itemPickUps = plugin.getPlayerData().getBoolean(
"PlayerData." + p.getUniqueId() + ".itemPickUps",
boolean persistedVanished = plugin.getVanishStateMgr().isVanished(p.getUniqueId());
boolean itemPickUps = plugin.getVanishStateMgr().getItemPickUps(p.getUniqueId(),
plugin.getSettings().getBoolean("InvisibilityFeatures.DefaultPickUpItemsOption"));
plugin.createVanishPlayer(p, itemPickUps);
if (vanished && plugin.getSettings().getBoolean("VanishStateFeatures.CheckPermissionOnLogin", false)
&& !CommandAction.VANISH_SELF.checkPermission(p, plugin)) {
vanished = false;
}
if (!vanished && p.hasPermission("sv.joinvanished")
&& plugin.getSettings().getBoolean("VanishStateFeatures.AutoVanishOnJoin", false)) {
plugin.getVanishStateMgr().setVanishedState(p.getUniqueId(), p.getName(), true, null);
vanished = true;
}
if (vanished) {
// hide self
for (Player onlinePlayer : Bukkit.getOnlinePlayers())
if (!plugin.hasPermissionToSee(onlinePlayer, p))
plugin.getVisibilityChanger().getHider().setHidden(p, onlinePlayer, true);
if (persistedVanished
&& plugin.getSettings().getBoolean("VanishStateFeatures.CheckPermissionOnLogin", false)
&& !CommandAction.VANISH_SELF.checkPermission(p, plugin))
{
// Persist the auto-unvanish so reconcileVisibility() and TAB-OG's
// canSee() do not keep hiding the player based on stale saved state.
plugin.getVanishStateMgr().setVanishedState(p.getUniqueId(), p.getName(), false, null);
persistedVanished = false;
}
// hide others
for (Player onlinePlayer : Bukkit.getOnlinePlayers())
if (plugin.getVanishStateMgr().isVanished(onlinePlayer.getUniqueId())
&& !plugin.hasPermissionToSee(p, onlinePlayer))
plugin.getVisibilityChanger().getHider().setHidden(onlinePlayer, p, true);
if (persistedVanished) {
p.setMetadata("vanished", new FixedMetadataValue(plugin, true));
} else {
p.removeMetadata("vanished", plugin);
}
plugin.reconcileVisibility(p);
} catch (Exception er) {
plugin.logException(er);
}
}
}
@@ -29,58 +29,91 @@ public class PlayerBlockModifyListener implements Listener {
private final SuperVanish plugin;
public PlayerBlockModifyListener(SuperVanish plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.HIGH)
public void onInteract(PlayerInteractEvent e) {
try {
if (!plugin.getVanishStateMgr().isVanished(e.getPlayer().getUniqueId()))
return;
if (e.getAction().equals(Action.PHYSICAL) && e.getClickedBlock() != null) {
if (!plugin.getSettings().getBoolean("InvisibilityFeatures.DisablePressurePlates"))
return;
String material = e.getClickedBlock().getType().toString();
List<String> disallowedMaterials = Arrays.asList("STONE_PLATE", "GOLD_PLATE", "IRON_PLATE",
"WOOD_PLATE"/* <- LEGACY*/, "TRIPWIRE", "PRESSURE_PLATE");
"WOOD_PLATE"/* <- LEGACY */, "TRIPWIRE", "PRESSURE_PLATE");
for (String disallowedMaterial : disallowedMaterials)
if (material.equals(disallowedMaterial) || material.contains(disallowedMaterial)) {
e.setCancelled(true);
}
}
} catch (Exception er) {
plugin.logException(er);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlace(BlockPlaceEvent e) {
try {
if (plugin.getSettings().getBoolean("RestrictiveOptions.PreventBlockPlacing")) {
Player p = e.getPlayer();
Collection<UUID> vanishedPlayers = plugin.getVanishStateMgr().getOnlineVanishedPlayers();
if (vanishedPlayers.contains(p.getUniqueId()) && !p.hasPermission("sv.placeblocks")) {
e.setCancelled(true);
plugin.sendMessage(e.getPlayer(), "BlockPlaceDenied", e.getPlayer());
}
}
} catch (Exception er) {
plugin.logException(er);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onBreak(BlockBreakEvent e) {
try {
if (plugin.getSettings().getBoolean("RestrictiveOptions.PreventBlockBreaking")) {
Player p = e.getPlayer();
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId()) && !p.hasPermission("sv.breakblocks")) {
e.setCancelled(true);
plugin.sendMessage(e.getPlayer(), "BlockBreakDenied", e.getPlayer());
}
}
} catch (Exception er) {
plugin.logException(er);
}
}
}
@@ -10,9 +10,7 @@ package de.myzelyam.supervanish.listeners;
import de.myzelyam.supervanish.SuperVanish;
import de.myzelyam.supervanish.commands.CommandAction;
import de.myzelyam.supervanish.features.Broadcast;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
@@ -24,50 +22,55 @@ public class QuitListener implements EventExecutor, Listener {
private final SuperVanish plugin;
public QuitListener(SuperVanish plugin) {
this.plugin = plugin;
}
@Override
public void execute(Listener l, Event event) {
try {
if (event instanceof PlayerQuitEvent) {
PlayerQuitEvent e = (PlayerQuitEvent) event;
FileConfiguration config = plugin.getConfig();
Player p = e.getPlayer();
// if is invisible
if (plugin.getVanishStateMgr().isVanished(p.getUniqueId())) {
// remove action bar
if (plugin.getActionBarMgr() != null && plugin.getSettings().getBoolean(
"MessageOptions.DisplayActionBar")) {
if (plugin.getActionBarMgr() != null
&& plugin.getSettings().getBoolean("MessageOptions.DisplayActionBar"))
{
plugin.getActionBarMgr().removeActionBar(p);
}
// check auto-reappear-option
boolean noMsg = false;
if (plugin.getSettings().getBoolean("VanishStateFeatures.ReappearOnQuit")
|| plugin.getSettings().getBoolean("VanishStateFeatures.CheckPermissionOnQuit")
&& !CommandAction.VANISH_SELF.checkPermission(p, plugin)) {
&& !CommandAction.VANISH_SELF.checkPermission(p, plugin))
{
plugin.getVanishStateMgr().setVanishedState(p.getUniqueId(), p.getName(), false, null);
// collision
try {
//noinspection deprecation
p.spigot().setCollidesWithEntities(true);
} catch (NoClassDefFoundError | NoSuchMethodError ignored) {
}
// check if it should handle the quit msg
if (!config.getBoolean("MessageOptions.ReappearOnQuitHideLeaveMsg"))
noMsg = true;
}
// check remove-quit-msg option
if (!noMsg && config.getBoolean("MessageOptions.HideRealJoinQuitMessages")) {
e.setQuitMessage(null);
Broadcast.announceSilentQuit(p, plugin);
}
}
// remove VanishPlayer
plugin.removeVanishPlayer(plugin.getVanishPlayer(p));
}
} catch (Exception er) {
plugin.logException(er);
}
}
}
}
@@ -17,37 +17,68 @@ import org.bukkit.event.Listener;
import org.bukkit.event.server.TabCompleteEvent;
import java.util.Iterator;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class TabCompleteListener implements Listener {
private final SuperVanish plugin;
private boolean errorLogged = false;
public TabCompleteListener(SuperVanish plugin) {
this.plugin = plugin;
}
@EventHandler
public void onTabComplete(TabCompleteEvent e) {
try {
if (!(e.getSender() instanceof Player)) return;
if (!(e.getSender() instanceof Player))
return;
Player p = (Player) e.getSender();
Set<String> hiddenNames = plugin.getVanishStateMgr().getOnlineVanishedPlayers().stream()
.map(Bukkit::getPlayer).filter(Objects::nonNull)
.filter(vanishedPlayer -> !plugin.canSee(p, vanishedPlayer)).map(HumanEntity::getName)
.map(name -> name.toLowerCase(Locale.ENGLISH)).collect(Collectors.toSet());
Iterator<String> it = e.getCompletions().iterator();
while (it.hasNext()) {
String completion = it.next();
boolean allowedCompletion = plugin.getVanishStateMgr().getOnlineVanishedPlayers().stream()
.map(Bukkit::getPlayer).filter(Objects::nonNull)
.filter(vanishedPlayer -> !plugin.canSee(p, vanishedPlayer))
.map(HumanEntity::getName)
.noneMatch(name -> name.equalsIgnoreCase(completion));
boolean allowedCompletion = !hiddenNames.contains(completion.toLowerCase(Locale.ENGLISH));
if (!allowedCompletion) {
it.remove();
}
}
} catch (UnsupportedOperationException uoe) {
if (!errorLogged) {
plugin.getLogger().warning("UnsupportedOperationException while modifying TabCompleteEvent");
errorLogged = true;
}
} catch (Exception er) {
plugin.logException(er);
if (!errorLogged) {
plugin.logException(er);
errorLogged = true;
}
}
}
}
@@ -22,23 +22,35 @@ public class WorldChangeListener implements Listener {
private final SuperVanish plugin;
public WorldChangeListener(SuperVanish plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onWorldChange(PlayerChangedWorldEvent e) {
try {
final Player p = e.getPlayer();
if (!plugin.getVanishStateMgr().isVanished(p.getUniqueId()))
return;
// check auto-reappear option
if (plugin.getSettings().getBoolean("VanishStateFeatures.ReappearOnWorldChange")
|| plugin.getSettings().getBoolean("VanishStateFeatures.CheckPermissionOnWorldChange")
&& !CommandAction.VANISH_SELF.checkPermission(p, plugin)) {
&& !CommandAction.VANISH_SELF.checkPermission(p, plugin))
{
plugin.getVisibilityChanger().showPlayer(p);
}
} catch (Exception er) {
plugin.logException(er);
}
}
}
@@ -1,143 +0,0 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.net;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import javax.net.ssl.HttpsURLConnection;
import lombok.Getter;
public class UpdateNotifier {
// 20 minutes
private static final long CHECK_INTERVAL = 20 * 60 * 20;
private final SuperVanish plugin;
private final BukkitTask checkTask;
@Getter
private final String currentVersion;
private final Set<UUID> notifiedPlayers = new HashSet<>();
@Getter
private volatile String latestVersion;
private boolean notifiedConsole = false;
public UpdateNotifier(final SuperVanish plugin) {
this.plugin = plugin;
currentVersion = plugin.getDescription().getVersion();
checkTask = start();
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onJoin(final PlayerJoinEvent e) {
new BukkitRunnable() {
@Override
public void run() {
if (!isUpToDate())
notifyPlayer(e.getPlayer());
}
}.runTaskLater(plugin, 2);
}
}, plugin);
}
public boolean isUpToDate() {
try {
if (latestVersion == null) throw new NumberFormatException();
int comparision = plugin.getVersionUtil().compareVersions(currentVersion, latestVersion);
return comparision >= 0;
} catch (NumberFormatException e) {
return currentVersion.equals(latestVersion);
}
}
private void notifyPlayer(Player p) {
if (p.hasPermission("sv.notify") && latestVersion != null) {
if (notifiedPlayers.contains(p.getUniqueId())) return;
notifiedPlayers.add(p.getUniqueId());
plugin.sendMessage(p,
plugin.getMessage("PluginOutdated").replace("%new%", latestVersion)
.replace("%current%", currentVersion), p);
}
}
private void notifyAdmins() {
for (Player p : plugin.getServer().getOnlinePlayers()) {
notifyPlayer(p);
}
}
private void notifyConsole() {
if (!notifiedConsole) {
plugin.log(Level.INFO, "Your current version of SuperVanish is outdated" +
" - New version: '" + latestVersion + "'; Currently: '" + currentVersion + "'");
notifiedConsole = true;
}
}
private BukkitTask start() {
if (checkTask != null) throw new IllegalStateException("Task is already running");
return new BukkitRunnable() {
@Override
public void run() {
String latestVersion = fetchLatestVersion();
UpdateNotifier.this.latestVersion = latestVersion.equals("Error")
? UpdateNotifier.this.latestVersion == null
? currentVersion
: UpdateNotifier.this.latestVersion
: latestVersion;
if (!isUpToDate())
new BukkitRunnable() {
@Override
public void run() {
notifyConsole();
if (plugin.getSettings().getBoolean(
"MiscellaneousOptions.UpdateChecker.NotifyAdmins")) notifyAdmins();
}
}.runTask(plugin);
}
}.runTaskTimerAsynchronously(plugin, 0, CHECK_INTERVAL);
}
private String fetchLatestVersion() {
try {
HttpsURLConnection con = (HttpsURLConnection) new URL(
"https://api.spigotmc.org/legacy/update.php?resource=1331").openConnection();
con.setConnectTimeout(20 * 1000);
con.setReadTimeout(20 * 1000);
String version;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
version = reader.readLine();
}
con.disconnect();
if (version.length() <= 7)
return version;
else throw new RuntimeException("'" + version + "' is not a valid version");
} catch (Exception e) {
plugin.log(Level.WARNING, "Failed to check for an update: "
+ e.getMessage());
return "Error";
}
}
}
@@ -7,33 +7,91 @@ import org.bukkit.entity.Player;
public class BukkitPlayerHidingUtil {
private BukkitPlayerHidingUtil() {
}
public static void hidePlayer(Player player, Player viewer, SuperVanish plugin) {
if (isNewPlayerHidingAPISupported(viewer))
viewer.hidePlayer(plugin, player);
else
//noinspection deprecation
viewer.hidePlayer(player);
try {
if (isNewPlayerHidingAPISupported(plugin)) {
Player.class.getMethod("hidePlayer", org.bukkit.plugin.Plugin.class, Player.class).invoke(viewer,
plugin, player);
} else {
Player.class.getMethod("hidePlayer", Player.class).invoke(viewer, player);
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to hide player " + player.getName() + " from " + viewer.getName(), e);
}
}
public static void showPlayer(Player player, Player viewer, SuperVanish plugin) {
if (isNewPlayerHidingAPISupported(viewer))
viewer.showPlayer(plugin, player);
else
//noinspection deprecation
viewer.showPlayer(player);
try {
if (isNewPlayerHidingAPISupported(plugin)) {
Player.class.getMethod("showPlayer", org.bukkit.plugin.Plugin.class, Player.class).invoke(viewer,
plugin, player);
} else {
Player.class.getMethod("showPlayer", Player.class).invoke(viewer, player);
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to show player " + player.getName() + " to " + viewer.getName(), e);
}
}
public static boolean isNewPlayerHidingAPISupported(Player testPlayer) {
return false; // New API doesn't seem to work with SuperVanish
/*
Class<? extends Player> playerClass = testPlayer.getClass();
try {
playerClass.getMethod("hidePlayer", Plugin.class, Player.class);
} catch (NoSuchMethodException e) {
return false;
/**
* Nuclear show: clears every hide ref that Vanish-OG could plausibly be
* responsible for on this (viewer, player) pair. CraftPlayer tracks hides
* per-plugin in {@code invertedVisibilityEntities}, and an entity stays hidden
* until *all* refs in its set are gone. Essentials'
* {@code User#setVanished(true)} and
* {@code EssentialsPlayerListener#onPlayerJoin} both call the deprecated
* {@code hidePlayer(Player)} form, which registers a {@code null} plugin ref
* that Vanish-OG's normal {@code showPlayer(Plugin, Player)} cannot remove — so
* {@code /sv cleanup} must also call the deprecated {@code showPlayer(Player)}
* to drop it. Without this step, players stay invisible to each other even
* after cleanup wipes persisted vanish state and Vanish-OG's own hide map.
*/
public static void showPlayerAggressive(Player player, Player viewer, SuperVanish plugin) {
showPlayer(player, viewer, plugin);
if (isNewPlayerHidingAPISupported(plugin)) {
try {
Player.class.getMethod("showPlayer", Player.class).invoke(viewer, player);
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to legacy-show " + player.getName() + " to " + viewer.getName(), e);
}
}
return true;*/
}
public static boolean isNewPlayerHidingAPISupported(SuperVanish plugin) {
return plugin.getVersionUtil().isOneDotXOrHigher(19);
}
}
@@ -3,4 +3,5 @@ package de.myzelyam.supervanish.utils;
public interface ExceptionHandler {
void handle(Exception e);
}
@@ -10,70 +10,110 @@ import java.util.logging.Level;
public class ExceptionLogger {
private ExceptionLogger() {
}
private static boolean isSensitiveKey(String key) {
String lower = key.toLowerCase(java.util.Locale.ROOT);
return lower.contains("password") || lower.contains("secret") || lower.contains("token")
|| lower.contains("apikey") || lower.contains("api-key") || lower.contains("api_key")
|| lower.contains("credential");
}
public static void logException(Throwable e, SuperVanish plugin) {
try {
final boolean realEx = e != null;
Level loggingLevel = realEx ? Level.WARNING : Level.INFO;
if (realEx) plugin.log(loggingLevel, "Unknown exception occurred!");
else plugin.log(loggingLevel, "Printing information...");
if (plugin.getConfigMgr().isSettingsUpdateRequired()
|| plugin.getConfigMgr().isMessagesUpdateRequired()) {
if (realEx) plugin.log(loggingLevel, "You have an outdated configuration, " +
"regenerating it by using '/sv recreatefiles' might fix this problem!");
else plugin.log(loggingLevel, "Configuration is outdated.");
} else if (realEx) plugin.log(loggingLevel, "Please report this issue!");
if (!realEx) e = new RuntimeException("Information for reporting an issue");
if (realEx)
plugin.log(loggingLevel, "Unknown exception occurred!");
else
plugin.log(loggingLevel, "Printing information...");
if (plugin.getConfigMgr().isMessagesUpdateRequired()) {
if (realEx)
plugin.log(loggingLevel, "Your config files may need to be recreated. "
+ "Running '/sv recreatefiles' might fix this problem.");
else
plugin.log(loggingLevel, "Config file recreation may be required.");
} else if (realEx)
plugin.log(loggingLevel, "Please report this issue!");
if (!realEx)
e = new RuntimeException("Information for reporting an issue");
plugin.log(loggingLevel, "Message: ");
plugin.log(loggingLevel, " " + e.getMessage());
plugin.log(loggingLevel, "General information: ");
StringBuilder plugins = new StringBuilder();
for (Plugin pl : Bukkit.getServer().getPluginManager().getPlugins()) {
if (pl.getName().equalsIgnoreCase("SuperVanish")) continue;
plugins.append(pl.getName()).append(" v")
.append(pl.getDescription().getVersion()).append(", ");
if (pl.getName().equalsIgnoreCase("Vanish-OG"))
continue;
plugins.append(pl.getName()).append(" v").append(pl.getPluginMeta().getVersion()).append(", ");
}
plugins = new StringBuilder(plugins.substring(0, plugins.length() - 1));
plugin.log(loggingLevel, " ServerVersion: " + plugin.getServer().getVersion());
plugin.log(loggingLevel, " PluginVersion: "
+ plugin.getDescription().getVersion());
plugin.log(loggingLevel, " PluginVersion: " + plugin.getPluginMeta().getVersion());
plugin.log(loggingLevel, " ServerPlugins: " + plugins);
try {
plugin.log(loggingLevel, "Settings:");
plugin.log(loggingLevel, " MsgsVersion: "
+ plugin.getMessages().getString("MessagesVersion"));
plugin.log(loggingLevel, " MsgsVersion: " + plugin.getMessages().getString("MessagesVersion"));
StringBuilder settings = new StringBuilder("||");
for (String key : plugin.getSettings().getKeys(true)) {
if (!plugin.getSettings().getString(key).contains("MemorySection"))
settings.append(key).append(">")
.append(plugin.getSettings().getString(key)).append("||");
if (!plugin.getSettings().getString(key).contains("MemorySection")) {
String value = isSensitiveKey(key) ? "<redacted>" : plugin.getSettings().getString(key);
settings.append(key).append(">").append(value).append("||");
}
}
plugin.log(loggingLevel, " Settings: " + settings);
} catch (Exception er) {
plugin.log(Level.SEVERE, ">> Error occurred while trying to print config info <<");
}
plugin.log(loggingLevel, "StackTrace: ");
e.printStackTrace();
if (realEx) {
if (plugin.getConfigMgr().isSettingsUpdateRequired()
|| plugin.getConfigMgr().isMessagesUpdateRequired())
plugin.log(loggingLevel, "You have an outdated configuration, " +
"regenerating it by using '/sv recreatefiles' might fix this problem!");
if (plugin.getConfigMgr().isMessagesUpdateRequired())
plugin.log(loggingLevel, "Your config files may need to be recreated. "
+ "Running '/sv recreatefiles' might fix this problem.");
plugin.log(loggingLevel, "Please include this information");
plugin.log(loggingLevel, "if you report the issue.");
} else
plugin.log(loggingLevel, "End of information.");
} catch (Exception e2) {
plugin.log(Level.WARNING,
"An exception occurred while trying to print a detailed stacktrace, " +
"printing an undetailed stacktrace of both exceptions:");
plugin.log(Level.WARNING, "An exception occurred while trying to print a detailed stacktrace, "
+ "printing an undetailed stacktrace of both exceptions:");
plugin.log(Level.SEVERE, "ORIGINAL EXCEPTION:");
if (e != null) {
e.printStackTrace();
}
plugin.log(Level.SEVERE, "SECOND EXCEPTION:");
e2.printStackTrace();
}
}
}
@@ -9,5 +9,7 @@
package de.myzelyam.supervanish.utils;
public interface Requirement<T> {
boolean fulfilledBy(T testSubject);
}
@@ -7,40 +7,62 @@ import java.util.logging.Level;
public abstract class Validation {
public static void checkNotNull(Object... objects) {
checkNotNull(null, objects);
}
public static void checkIsTrue(boolean... bool) {
checkIsTrue(null, bool);
}
public static void checkNotNull(String message, Object... objects) {
for (Object obj : objects) {
if (obj == null) {
if (message != null)
log(Level.SEVERE, message);
throw new IllegalArgumentException(message == null ? "" : message);
}
}
}
public static void checkIsTrue(String message, boolean... booleans) {
for (boolean bool : booleans) {
if (!bool) {
if (message != null)
log(Level.SEVERE, message);
throw new IllegalArgumentException(message == null ? "" : message);
}
}
}
private static void log(Level level, String message) {
try {
Class.forName("org.bukkit.plugin.java.JavaPlugin");
Bukkit.getLogger().log(level, message);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@@ -1,39 +1,65 @@
package de.myzelyam.supervanish.utils;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import de.myzelyam.supervanish.SuperVanish;
public class VersionUtil {
private final SuperVanish plugin;
private final String version;
private final String minecraftVersion;
public VersionUtil(SuperVanish plugin) {
this.plugin = plugin;
version = plugin.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
// Saves versions in the format x.x.x (e.g. 1.20.1).
minecraftVersion = plugin.getServer().getBukkitVersion().split(Pattern.quote("-"))[0];
}
public int compareVersions(String version1, String version2) {
String[] levels1 = version1.split("\\.");
String[] levels2 = version2.split("\\.");
int length = Math.max(levels1.length, levels2.length);
final String[] levels1 = version1.split("\\.");
final String[] levels2 = version2.split("\\.");
final int length = Math.max(levels1.length, levels2.length);
for (int i = 0; i < length; i++) {
Integer v1 = i < levels1.length ? Integer.parseInt(levels1[i]) : 0;
Integer v2 = i < levels2.length ? Integer.parseInt(levels2[i]) : 0;
int compare = v1.compareTo(v2);
final Integer v1 = i < levels1.length ? Integer.parseInt(levels1[i]) : 0;
final Integer v2 = i < levels2.length ? Integer.parseInt(levels2[i]) : 0;
final int compare = v1.compareTo(v2);
if (compare != 0) {
return compare;
}
}
return 0;
}
public boolean isOneDotX(int majorRelease) {
return version.contains("v1_" + majorRelease + "_R");
return minecraftVersion.equals("1." + majorRelease)
|| StringUtils.startsWith(minecraftVersion, "1." + majorRelease + ".");
}
public boolean isOneDotXOrHigher(int majorRelease) {
for (int i = majorRelease; i < 20; i++)
if (version.contains("v1_" + i + "_R")) return true;
return version.contains("v2_");
for (int i = majorRelease; i < 40; i++) {
if (minecraftVersion.equals("1." + i) || StringUtils.startsWith(minecraftVersion, "1." + i + ".")) {
return true;
}
}
return StringUtils.startsWith(minecraftVersion, "2.");
}
}
}
@@ -14,13 +14,11 @@ import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import de.myzelyam.supervanish.SuperVanish;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.ChatColor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
@@ -30,65 +28,95 @@ public class ActionBarMgr {
private final List<Player> actionBars = new ArrayList<>();
public ActionBarMgr(SuperVanish plugin) {
this.plugin = plugin;
startTask();
}
private void startTask() {
new BukkitRunnable() {
@Override
public void run() {
for (Player p : actionBars) {
try {
sendActionBar(p, plugin.replacePlaceholders(plugin.getMessage("ActionBarMessage"), p));
sendActionBar(p, plugin.expandPlaceholders(p, plugin.getMessage("ActionBarMessage"), p));
} catch (Exception | NoSuchMethodError | NoClassDefFoundError e) {
cancel();
plugin.logException(e);
plugin.getLogger().warning("IMPORTANT: Please make sure that you are using the latest " +
"dev-build of ProtocolLib and that your server is up-to-date! This error likely " +
"happened inside of ProtocolLib code which is out of SuperVanish's control. It's part " +
"of an optional feature module and can be removed safely by disabling " +
"DisplayActionBar in the config file. Please report this " +
"error if you can reproduce it on an up-to-date server with only latest " +
"ProtocolLib and latest SV installed.");
plugin.getLogger().warning("IMPORTANT: Please make sure that you are using the latest "
+ "dev-build of ProtocolLib and that your server is up-to-date! This error likely "
+ "happened inside of ProtocolLib code which is out of Vanish-OG's control. It's part "
+ "of an optional feature module and can be removed safely by disabling "
+ "DisplayActionBar in the config file. Please report this "
+ "error if you can reproduce it on an up-to-date server with only latest "
+ "ProtocolLib and latest Vanish-OG installed.");
}
}
}
}.runTaskTimer(plugin, 0, 2 * 20);
}
private void sendActionBar(Player p, String bar) {
private void sendActionBar(Player p, Component bar) {
try {
Class.forName("net.md_5.bungee.api.chat.ComponentBuilder");
p.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(bar));
} catch (ClassNotFoundException | NoSuchMethodError | NoClassDefFoundError er) {
String json = "{\"text\": \"" + ChatColor.translateAlternateColorCodes('&', bar) + "\"}";
p.sendActionBar(bar);
} catch (NoSuchMethodError | NoClassDefFoundError er) {
String json = GsonComponentSerializer.gson().serialize(bar);
WrappedChatComponent msg = WrappedChatComponent.fromJson(json);
PacketContainer chatMsg = new PacketContainer(PacketType.Play.Server.CHAT);
chatMsg.getChatComponents().write(0, msg);
if (plugin.getVersionUtil().isOneDotXOrHigher(12))
try {
chatMsg.getChatTypes().write(0, EnumWrappers.ChatType.GAME_INFO);
} catch (NoSuchMethodError e) {
p.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText
("SuperVanish: Please update ProtocolLib"));
p.sendActionBar(Component.text("Vanish-OG: Please update ProtocolLib"));
}
else
chatMsg.getBytes().write(0, (byte) 2);
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(p, chatMsg);
} catch (InvocationTargetException e) {
} catch (Exception e) {
throw new RuntimeException("Cannot send packet " + chatMsg, e);
}
}
}
public void addActionBar(Player p) {
actionBars.add(p);
}
public void removeActionBar(Player p) {
actionBars.remove(p);
}
}
@@ -1,105 +0,0 @@
/*
* Copyright © 2015, Leon Mangler and the SuperVanish contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package de.myzelyam.supervanish.visibility;
import de.myzelyam.api.vanish.PlayerVanishStateChangeEvent;
import de.myzelyam.supervanish.SuperVanish;
import org.bukkit.Bukkit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
public class FileVanishStateMgr extends VanishStateMgr {
private final SuperVanish plugin;
public FileVanishStateMgr(SuperVanish plugin) {
super(plugin);
this.plugin = plugin;
}
@Override
public boolean isVanished(final UUID uuid) {
return getVanishedPlayersOnFile().contains(uuid);
}
@Override
public void setVanishedState(final UUID uuid, String name, boolean hide, String causeName) {
PlayerVanishStateChangeEvent event = new PlayerVanishStateChangeEvent(uuid, name, hide, causeName);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return;
List<String> vanishedPlayerUUIDStrings = plugin.getPlayerData().getStringList("InvisiblePlayers");
if (hide)
vanishedPlayerUUIDStrings.add(uuid.toString());
else
vanishedPlayerUUIDStrings.remove(uuid.toString());
plugin.getPlayerData().set("InvisiblePlayers", vanishedPlayerUUIDStrings);
if (hide)
plugin.getPlayerData().set("PlayerData." + uuid + ".information.name", name);
plugin.getConfigMgr().getPlayerDataFile().save();
}
@Override
public Set<UUID> getVanishedPlayers() {
return getVanishedPlayersOnFile();
}
@Override
public Collection<UUID> getOnlineVanishedPlayers() {
Set<UUID> onlineVanishedPlayers = new HashSet<>();
for (UUID vanishedUUID : getVanishedPlayers()) {
if (Bukkit.getPlayer(vanishedUUID) != null)
onlineVanishedPlayers.add(vanishedUUID);
}
return onlineVanishedPlayers;
}
public UUID getVanishedUUIDFromNameOnFile(String name) {
for (UUID uuid : getVanishedPlayersOnFile()) {
if (plugin.getPlayerData().getString("PlayerData." + uuid + ".information.name")
.equalsIgnoreCase(name)) {
return uuid;
}
}
return null;
}
private Set<UUID> getVanishedPlayersOnFile() {
List<String> vanishedPlayerUUIDStrings = plugin.getPlayerData().getStringList("InvisiblePlayers");
Set<UUID> vanishedPlayerUUIDs = new HashSet<>();
for (String uuidString : new ArrayList<>(vanishedPlayerUUIDStrings)) {
try {
vanishedPlayerUUIDs.add(UUID.fromString(uuidString));
} catch (IllegalArgumentException e) {
vanishedPlayerUUIDStrings.remove(uuidString);
plugin.log(Level.WARNING,
"The data.yml file contains an invalid player uuid," +
" deleting it.");
plugin.getPlayerData().set("InvisiblePlayers", vanishedPlayerUUIDStrings);
plugin.getConfigMgr().getPlayerDataFile().save();
}
}
return vanishedPlayerUUIDs;
}
private void setVanishedPlayersOnFile(Set<UUID> vanishedPlayers) {
List<String> vanishedPlayerUUIDStrings = new ArrayList<>();
for (UUID uuid : vanishedPlayers)
vanishedPlayerUUIDStrings.add(uuid.toString());
plugin.getPlayerData().set("InvisiblePlayers",
vanishedPlayerUUIDStrings);
plugin.getConfigMgr().getPlayerDataFile().save();
}
}
Loaded 100 of 114 files, more files were not shown because too many files have changed in this diff. Show more