Compare commits

..
34 Commits
Author SHA1 Message Date
Warrior 736171a3ae Run smite with entity scheduler 2026-05-03 13:35:38 -07:00
Warrior eb9b7dc74c Modify thunder on global thread 2026-05-03 13:35:38 -07:00
Warrior bb0f9f3c51 Fix retrieving tile entity count for gc command 2026-05-03 13:35:38 -07:00
Warrior 853ac1ea4b Fix merge artifact (?) 2026-05-03 13:35:38 -07:00
Warrior e7461bfd38 Run kill command on entity thread 2026-05-03 13:35:38 -07:00
JRoy 63dcfa2333 sure 2026-02-28 15:20:36 -08:00
JRoy 4423bc824e Merge branch '2.x' into fork/Warriorrrr/feat/folia/merge-2.x-changes
# Conflicts:
#	Essentials/src/main/java/com/earth2me/essentials/Essentials.java
#	Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java
2026-02-28 15:19:54 -08:00
Warrior b30021321a Move economy layers initialization to after providers
EconomyLayers relies on the scheduler to be initialized to enable properly
2026-02-13 20:12:00 +01:00
Warrior 00e35092ad Update scheduling providers to work with new provider system 2026-02-13 19:59:33 +01:00
Warrior 25685a8a64 Merge branch '2.x' into feat/folia/merge-2.x-changes 2026-02-13 19:39:46 +01:00
Josh Roy d73ed137fa Fix time/weather commands 2023-08-22 12:12:33 -04:00
Josh Roy d0493ccd2a Merge remote-tracking branch 'upstream/2.x' into refactor/folia
# Conflicts:
#	Essentials/src/main/java/com/earth2me/essentials/commands/Commandskull.java
2023-08-22 11:37:36 -04:00
Josh Roy 0c8bc16c3d Fix time command 2023-07-27 19:59:56 -04:00
Josh Roy d4ebaf61d4 Fix weather command 2023-07-27 19:38:32 -04:00
Josh Roy 1a108b5e2e Bump folia version 2023-07-27 19:35:45 -04:00
Josh Roy 10fc005652 Merge remote-tracking branch 'upstream/2.x' into refactor/folia
# Conflicts:
#	EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java
2023-07-27 19:30:00 -04:00
Josh Roy 4256909eee Fix folia init tasks never getting called LOLW 2023-04-26 21:28:33 -04:00
Josh Roy 9133dce3eb Merge branch '2.x' into refactor/folia 2023-04-15 20:34:56 -04:00
Josh Roy ec5007c07e fix wrong period/timeunit for folia scheduling 2023-04-12 18:45:22 -04:00
Josh Roy 4cb861badc Run interaction commands async for now (hopefully okay) 2023-04-02 21:11:55 -04:00
Josh Roy 7279be7850 allow DiscordMessageEvent calls from any context 2023-04-02 20:58:56 -04:00
Josh Roy 2ba1eb0cf9 fix "Fix moo" 2023-04-01 17:42:38 -04:00
Josh Roy 7216fddfbe Add helper methods for ensuring thread contexts 2023-03-30 13:40:13 -04:00
Josh Roy 2d8cc827b9 Add method for checking the global thread 2023-03-30 13:31:16 -04:00
Josh Roy 4ff9286a79 Move over some discord things 2023-03-30 13:28:41 -04:00
Josh Roy 9a5ac3cad8 Fix tests 2023-03-30 13:20:29 -04:00
Josh Roy 05a8aa8883 Switch to Paper repo 2023-03-30 13:06:35 -04:00
Josh Roy 1d93ebfddd Fix moo 2023-03-29 19:59:30 -04:00
Josh Roy 04683ee43b Fix async entity dismounts 2023-03-29 19:57:57 -04:00
Josh Roy a649f978c5 Add some thread checking helper methods
pending PaperMC/Folia#5 for global region helpers
2023-03-28 21:57:24 -04:00
Josh Roy 20882940c5 Actually fire init tasks in Folia 2023-03-28 21:30:51 -04:00
Josh Roy 07fbf93001 Ensure nuke commands runs on correct threads 2023-03-28 21:23:27 -04:00
Josh Roy 0e4bab24cb Get like 70% of the plugin to work 2023-03-27 23:31:39 -04:00
Josh Roy 15c48d457a Add Folia providers 2023-03-27 23:29:42 -04:00
202 changed files with 2506 additions and 7166 deletions

No files matched your search

-270
View File
@@ -1,270 +0,0 @@
---
name: mc-update
description: Update EssentialsX for a new Minecraft version. Use when the user asks to update to, bump, or support a new Minecraft or Paper version (for example "update to 26.4", "add 26.3 mobs", "bump supported version"), or asks what must be checked for new mobs, items, wood types, armor, enchantments, potions, or Bukkit API changes.
---
# Minecraft update
This checklist comes from every Minecraft update PR from 1.14 to 26.3, and from the fix PRs that followed them.
Paths are relative to the repository root. `ESS` means `Essentials/src/main/java/com/earth2me/essentials`.
## Procedure
1. Find the old and new `paper-api` jars in `~/.gradle/caches/modules-2/files-2.1/io.papermc.paper/paper-api/`. If the new jar is not there, set `paperVersion` in `build-logic/src/main/kotlin/essentials.base-conventions.gradle.kts` and run `./gradlew :EssentialsX:compileJava` to download it.
2. Diff the constants of these classes between the two jars: `org.bukkit.entity.EntityType`, `org.bukkit.Material`, `org.bukkit.enchantments.Enchantment`, `org.bukkit.potion.PotionEffectType`, `org.bukkit.potion.PotionType`, `org.bukkit.TreeType`, and each `*$Variant` class under `org.bukkit.entity`. Use this command for each class:
```sh
unzip -p <jar> org/bukkit/entity/EntityType.class > /tmp/x.class && javap -p /tmp/x.class | grep 'public static final'
```
3. Sort each added, removed, or renamed constant into a section of part 2 or part 3 below.
4. Do part 1. Then do each section that applies.
5. Apply part 4 to every line you write.
6. Run `./gradlew :EssentialsX:compileJava`. Fix errors.
7. Do not commit unless the user asks.
8. Report per section: what changed, and what you skipped and why.
---
## 1. Every update
### 1.1 Version constants
1. Open `ESS/utils/VersionUtil.java`.
2. Add a constant `vXX_Y_R01 = BukkitVersion.fromString("XX.Y-R0.1-SNAPSHOT")`.
- For a patch release, change the string of the existing minor constant. Example: `v26_1_R01` holds `26.1.2`.
- For a minor release, add a new constant. Do not rename or delete an old constant. Old constants gate features. Deleting `v1_20_4_R01` caused #6460.
3. Add the constant to `supportedVersions`. Keep the `ImmutableSet.of(...)` syntax. `build-logic/src/main/kotlin/VersionDataTask.kt` parses it with a regex.
4. Start a server. Confirm `BukkitVersion.fromString(Bukkit.getBukkitVersion())` parses. Spigot 1.14.3 and Paper 26.1 both changed the string format.
### 1.2 Documentation
1. Update the supported versions sentence in `README.md`.
2. Regenerate `items.json` with ItemDbGenerator.
---
## 2. New content
### 2.1 New mob
1. Add an entry to `ESS/Mob.java`: `NAME("CamelName", Enemies.X, "ENTITY_TYPE")`.
- Use the string constructor. Do not use `EntityType.X`. The constant does not exist on old servers.
- Set the plural suffix if it is not `s`. Fish use `""`. Fox uses `es`.
- The display name must not contain a space.
- Boats and rafts are also `Mob` entries.
2. Add `EntityType` constant to `ESS/MobCompat.java` only if `MobData` needs it.
3. Add the mob to `protect.prevent.spawn` in `Essentials/src/main/resources/config.yml`.
4. Check `entityToDisplayName` in `providers/BaseProviders/.../SpawnerItemProvider.java` if the enum name does not title-case well.
### 2.2 New mob variant or data
1. Add entries to `ESS/MobData.java`. Use the string form `"kind:VARIANT"`. Example: `"wolf:PALE"`.
2. Add a `case "kind":` to the `setData` switch.
3. Add `setKindVariant(Entity, String)` to `MobCompat.java`. Gate it with `VersionUtil.getServerBukkitVersion().isLowerThan(vXX_Y_R01)`.
4. Use `RegistryUtil.valueOf(Variant.class, name)` for registry types. Do not use `Enum.valueOf`.
5. Do not call `NewClass.Variant.values()` in an enum initializer. Axolotl did this. It threw `NoClassDefFoundError` on 1.16 (#4376).
6. Catch `Throwable` around reflective lookups. Cow variant threw NPE on old servers (#6121).
7. For a boolean flag, add a `Data` constant and a branch in `setData`. Example: `GOAT_SCREAMING`.
### 2.3 New rideable or saddle mob
1. Add `SADDLE_<MOB>` to `MobData.java` with a `Data.<MOB>SADDLE` constant.
2. Add `set<Mob>Saddle(Entity, Player)` to `MobCompat.java`. Tame the mob. Set the owner. Set the saddle.
3. Check `ESS/craftbukkit/Inventories.java` if the mob adds a player inventory slot. Body and saddle slots (41, 42) broke `/clearinventory` in 1.21.6 (#6218).
### 2.4 New item or block
1. Check each `MaterialUtil` set that lists names by hand. See table.
2. Check `ESS/utils/LocationUtil.java`:
- Add a block that hurts a standing player to `DAMAGING_TYPES`. Magma, campfire, berry bush and wither rose were missed for 2 years (#3537).
- `HOLLOW_MATERIALS` comes from `Material.isTransparent()`. Add a passable block that is not transparent. Example: `LIGHT` (#4601). Remove a transparent block that is solid. Examples: `BARRIER`, `DIRT_PATH`, `FARMLAND`.
3. Check for a new event that reveals player position. Sculk sensor needed vanish handling in `EssentialsPlayerListener` (#5262).
| `ESS/utils/MaterialUtil.java` set | Add when |
|---|---|
| `HELMETS`, `CHESTPLATES`, `LEGGINGS`, `BOOTS` | New armor tier |
| `LEATHER_ARMOR` | New dyeable armor |
| `BEDS` | New bed. `STRAW_BED` in 26.3. |
| `BANNERS` | New banner colour |
| `SIGN_POSTS`, `WALL_SIGNS`, `HANGING_SIGNS`, `HANGING_WALL_SIGNS` | New wood type |
| `MOB_HEADS` | New head. `PIGLIN_HEAD` in 1.20. |
| `POTIONS` | New potion container |
| `EDITABLE_BOOKS` | New book type |
| `FIREWORKS`, `FIREWORK_CHARGE` | New firework item |
`EnumUtil.getAllMatching` skips a name that does not exist. Adding a name is safe on old servers.
### 2.5 Renamed item, block or entity
1. Grep `ESS` for `Material.OLD_NAME` and `EntityType.OLD_NAME`. Replace with `EnumUtil.getMaterial("NEW", "OLD")` or a `MobCompat` constant. `EntityType.PIG_ZOMBIE` in a static map broke 1.16 (#3412). `EntityType.FIREWORK` broke `/firework` in 1.20.6.
2. For a renamed `EntityType`, add `getEntityType("NEW", "OLD")` to `MobCompat.java`. Update `Mob.java`, `MobData.java` and `SpawnMob.java`.
### 2.6 New wood type
1. Add `<WOOD>_SIGN`, `<WOOD>_WALL_SIGN`, `<WOOD>_HANGING_SIGN`, `<WOOD>_WALL_HANGING_SIGN` to the four sign sets in `MaterialUtil.java`. Crimson and warped were missed in 1.16 (#3487).
2. Add `<WOOD>_BOAT` to `Mob.java`. Boats are separate entity types since 1.21.3.
3. Add `<WOOD>` to `MobCompat.BoatVariant` for servers before 1.21.3.
4. Add `<WOOD>_BOAT` to `MobData.java`.
5. Add `<WOOD>_CHEST_BOAT` to `Mob.java`.
### 2.7 New tree type
1. `Commandtree` reads `TreeType.values()`. It needs no code change.
2. Add the name to `treeCommandUsage` and `treeCommandUsage1` in `messages.properties`.
3. `Commandbigtree` has four hard-coded types. Add a case if the tree has a big variant.
4. Bukkit adds `TreeType` late. 26.3-pre-2 has no `POPLAR`.
### 2.8 New armor tier
1. Add the four pieces to `HELMETS`, `CHESTPLATES`, `LEGGINGS`, `BOOTS` in `MaterialUtil.java`.
2. Add a branch to the armor keyword chain in `ESS/SpawnMob.java`. The chain has `netherite`, `copper`, `diamond`, `gold`, `leather`, `iron`.
3. For horse armor, add `<TIER>_HORSE_ARMOR` to `MobData.java`. Example: `NETHERITE_HORSE_ARMOR`.
### 2.9 New enchantment
1. Add a `try { // XX.Y }` block to `ESS/Enchantments.java`.
2. Look up by name: `Enchantment.getByName("NAME")`. Check for null. Do not use `Enchantment.NAME`.
3. Add `ENCHANTMENTS.put("name", e)` and `ALIASENCHANTMENTS.put("alias", e)`.
4. Swift sneak (1.19) and lunge (1.21.11) were missed. Contributors added them months later.
5. Display and permission names come from `Enchantments.getRealName()`. It uses the key on 1.13+.
### 2.10 New potion effect or potion type
1. Add a `try { // XX.Y }` block to `ESS/Potions.java`. Catch `Throwable`.
2. Add `POTIONS.put("name", PotionEffectType.NAME)` and `ALIASPOTIONS.put(...)`.
3. `ModernPotionMetaProvider` maps `LONG_` and `STRONG_` prefixes. Check a new potion follows that pattern.
### 2.11 New banner pattern
No code change. `PatternTypeProvider` reads the registry.
### 2.12 New colour family
Check `MaterialUtil.getColorOf` for a colour name that is not a `DyeColor`.
### 2.13 New spawn egg
No code change. `FlatSpawnEggProvider` derives the egg from `EntityType.name() + "_SPAWN_EGG"`.
### 2.14 New command for new content
1. Gate the command with `VersionUtil`. Return `tl("unsupportedFeature")` on old servers. Examples: `/beezooka`, `/ice`.
2. Add the command to `plugin.yml` and `messages.properties`. Check message parameters. `iceOther` shipped without `{0}`.
---
## 3. API changes
### 3.1 Enum becomes a registry
Enchantment, PotionEffectType, Sound, PatternType, Villager.Profession, Cat.Type, Biome and Boat.Type all changed.
1. Replace `EnumUtil.valueOf` with `RegistryUtil.valueOf(Class, names...)`. Replace `.values()` with `RegistryUtil.values(Class)`.
2. If a static method moved from an enum to an interface, code compiled against the new API throws `IncompatibleClassChangeError` on old servers. `catch (Exception)` does not catch it. `PatternType.getByIdentifier` did this (#6553).
3. For such a case, add a provider pair:
- Interface in `providers/BaseProviders/src/main/java/net/ess3/provider/`.
- `Modern*Provider` in BaseProviders with `@ProviderData(weight = 1)` and a `@ProviderTest`.
- `Legacy*Provider` in `providers/1_12Provider` or `providers/1_8Provider`. These compile against the old API.
- Register with `providerFactory.registerProvider(Legacy.class, Modern.class)` in `Essentials.java`.
4. In a `@ProviderTest`, use `getMethod`, not `getDeclaredMethod`. 1.21 moved spawner methods to a super-interface (80bdc5269).
### 3.2 Removed API class
`PotionData`, `Potion`, `BannerMeta.setBaseColor` and `Achievement` were removed.
1. Move code that uses the removed class to a provider in `1_12Provider` or `1_8Provider`.
2. Add a modern provider in BaseProviders.
3. Remove the method from `OfflinePlayer`, `FakeWorld` and `FakeServer` if it was an override.
### 3.3 Changed method signature
1. Read the Bukkit diff for changed return types on methods EssentialsX calls.
2. A changed return type changes the call descriptor. The call throws `NoSuchMethodError` on old servers. `PlayerPickupArrowEvent#getArrow` did this (#3175). `InventoryView` becoming an interface did this (#5851).
3. Use a provider or reflection for the changed call.
### 3.4 New API methods on Player, World, Server
1. Add stubs to `providers/1_8Provider/.../OfflinePlayer.java` and `providers/1_12Provider/.../FakeWorld.java` if they fail to compile.
2. Tests use MockBukkit since 1.21.6. `FakeServer` no longer needs updates.
### 3.5 New event
1. Put the handler in a separate `*Listener_XX_Y` class.
2. Register it behind a `VersionUtil` check or `Class.forName`.
3. Do not put a new event in a listener that loads on old servers. `EntityTransformEvent` failed on 1.13.1 (#2942).
### 3.6 Spigot NMS obfuscation
1. Add `VXX_Y_RN` to `providers/NMSReflectionProvider/.../ReflUtil.java` if Spigot bumps the NMS revision.
2. Update the obfuscated `MinecraftServer#isRunning` name table in `ReflServerStateProvider.java`. This broke on 1.18, 1.19, 1.19.3, 1.20.6 and 1.21.10.
3. Paper uses `PaperServerStateProvider`. Test on Spigot to see this fail.
### 3.7 Paper internal classes
Paper config classes move. `ReflOnlineModeProvider` broke on 1.19 when config moved to `io.papermc.paper.configuration.GlobalConfiguration`. Check every reflective Paper access.
### 3.8 World height
1. Do not hard-code `0`, `-1`, `128` or `256` as a Y bound.
2. Use `WorldInfoProvider.getMinHeight`, `getMaxHeight` and `getLogicalHeight`.
3. Grep `LocationUtil`, `RandomTeleport`, `Commandtop`, `Commandsethome`, `Teleport`, `AsyncTeleport` and `SpawnMob`. 1.18 needed three fix PRs (#4657, #4667, #4715).
### 3.9 Item data components
1. Check `MetaItemStack.parseStringMeta`. The `[...]` component branch calls `UnsafeValues#modifyItemStack`. Its argument shape changed in 1.20.5 and again in 26.1 (#6570).
2. Check `Commandbook`. Writable and written books have separate meta since 1.20.6 (#6064).
3. Check `Commandskull`. Skull owner needs a resolved profile since 1.20.4 (#6188).
4. Check `MetaItemStack.canSpawn()`.
### 3.10 Vanilla messages
Check the vanilla changelog for a new client message that duplicates an EssentialsX message. 1.15 added "Respawn point set". `EssentialsPlayerListener` now gates `bedSet` (#2943).
### 3.11 Version string format
1. `BukkitVersion.VERSION_PATTERN` in `VersionUtil.java` must parse the new string.
2. Supported suffixes: `-snapshot-N`, `-pre-N`, `-rc-N`, `.build.N-channel`, `.local`, `-R0.1-SNAPSHOT`.
3. `compareDevSpecifier` orders `snapshot < pre < rc < release`.
4. `isSupportedVersion` compares major, minor and patch. A patch release needs a constant change.
5. 26.1 needed four fix PRs for this (#6480, #6483, #6500, #6501).
### 3.12 Adventure and Paper native paths
Each Paper API shift produced a gate:
- `Essentials.initAdventureFacet` gates the Paper facet at `v1_18_2_R01` (#6562).
- `EssentialsSpawnPlayerListener` gates `getRespawnLocation` at `v1_20_4_R01` (#6460).
- `EssentialsPlayerListener` gates configuration events at `v1_21_8_R01`.
Check each gate against the new version.
---
## 4. Compatibility rules
EssentialsX runs on 1.8.8 through the current version. Every update PR must keep that.
1. Do not reference a new `Material`, `EntityType`, `Enchantment` or `PotionEffectType` constant in a static field or enum initializer. Use `EnumUtil.getMaterial`, `EnumUtil.getEntityType` or a name lookup.
2. Catch `Throwable`, not `Exception`, around reflective lookups and provider selection. A swallowed `NoSuchFieldError` selected the wrong provider (7d6195375).
3. Use only Guava and Gson methods that exist in 1.8.8. `Ints.constrainToRange` and `JsonArray#add(String)` do not (#4708, 576866540).
4. Compile legacy providers in `1_8Provider` or `1_12Provider`. Code compiled against the new API can carry the wrong bytecode.
5. Gate with `isLowerThan(<next major>)`, not `isLowerThanOrEqualTo(<patch>)`. Forks use nonstandard revision numbers (43eff69a2).
6. Do not delete a `VersionUtil` constant.
7. Test on Paper latest, Spigot latest, 1.12.2 and 1.8.8. Most follow-up fixes in this history came from old servers.
---
## 5. Test
1. Run `./gradlew test`.
2. Run `./gradlew runServer`.
3. Run `/ess version`. Confirm the support status is FULL.
4. Run `/spawnmob <newmob>`, `/spawnmob <mob>:<variant>`.
5. Run `/give @s <newitem>`, `/give @s minecraft:<newitem>`.
6. Run `/enchant <newenchant>`, `/potion <neweffect>`.
7. Place an EssentialsX sign on each new sign type.
8. Run `/tree <newtree>` if Bukkit has the `TreeType`.
9. Run `/kit` with the new armor. Confirm auto-equip.
10. Teleport onto each new damaging block. Confirm `/tp` refuses.
11. Repeat on Spigot for `ReflServerStateProvider`.
+1 -1
View File
@@ -80,7 +80,7 @@ Java version:
bug fix on. If this feature does not apply to a server, strike through the server software using ~~strikethrough~~. If you have tested on other
environments, add a new line with relevant details.
-->
- [ ] Most recent Paper version (XX.YY.Z, git-Paper-BUILD)
- [ ] Most recent Paper version (1.XX.Y, git-Paper-BUILD)
- [ ] CraftBukkit/Spigot/Paper 1.12.2
- [ ] CraftBukkit 1.8.8
+1 -1
View File
@@ -80,7 +80,7 @@ Java version:
bug fix on. If this feature does not apply to a server, strike through the server software using ~~strikethrough~~. If you have tested on other
environments, add a new line with relevant details.
-->
- [ ] Most recent Paper version (XX.YY.Z, git-Paper-BUILD)
- [ ] Most recent Paper version (1.XX.Y, git-Paper-BUILD)
- [ ] CraftBukkit/Spigot/Paper 1.12.2
- [ ] CraftBukkit 1.8.8
+5 -59
View File
@@ -20,11 +20,11 @@ jobs:
with:
fetch-depth: 0
- name: Set up JDK 25
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 25
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
@@ -41,65 +41,11 @@ jobs:
report_paths: '**/build/test-results/test*/TEST-*.xml'
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: EssentialsX plugin jars
path: jars/
- name: Upload EssentialsX jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsX-*.jar
archive: false
- name: Upload EssentialsXAntiBuild jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXAntiBuild-*.jar
archive: false
- name: Upload EssentialsXChat jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXChat-*.jar
archive: false
- name: Upload EssentialsXDiscord jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXDiscord-*.jar
archive: false
- name: Upload EssentialsXDiscordLink jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXDiscordLink-*.jar
archive: false
- name: Upload EssentialsXGeoIP jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXGeoIP-*.jar
archive: false
- name: Upload EssentialsXProtect jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXProtect-*.jar
archive: false
- name: Upload EssentialsXSpawn jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXSpawn-*.jar
archive: false
- name: Upload EssentialsXXMPP jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXXMPP-*.jar
archive: false
- name: Deploy to Maven repo
if: ${{ success() && github.event_name == 'push' && github.repository == 'EssentialsX/Essentials' && github.ref == 'refs/heads/2.x' }}
env:
@@ -121,7 +67,7 @@ jobs:
cp -r EssentialsXMPP/build/docs/javadoc/ javadocs/EssentialsXMPP/
- name: Archive Javadocs
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: javadocs
path: javadocs/
@@ -139,7 +85,7 @@ jobs:
node-version: 22
- name: Download Javadocs
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
with:
name: javadocs
path: javadocs/
+3 -57
View File
@@ -27,11 +27,11 @@ jobs:
with:
fetch-depth: 0
- name: Set up JDK 25
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 25
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
@@ -48,61 +48,7 @@ jobs:
report_paths: '**/build/test-results/test*/TEST-*.xml'
- name: Archive plugin jars on GitHub
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: EssentialsX plugin jars
path: jars/
- name: Upload EssentialsX jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsX-*.jar
archive: false
- name: Upload EssentialsXAntiBuild jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXAntiBuild-*.jar
archive: false
- name: Upload EssentialsXChat jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXChat-*.jar
archive: false
- name: Upload EssentialsXDiscord jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXDiscord-*.jar
archive: false
- name: Upload EssentialsXDiscordLink jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXDiscordLink-*.jar
archive: false
- name: Upload EssentialsXGeoIP jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXGeoIP-*.jar
archive: false
- name: Upload EssentialsXProtect jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXProtect-*.jar
archive: false
- name: Upload EssentialsXSpawn jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXSpawn-*.jar
archive: false
- name: Upload EssentialsXXMPP jar
uses: actions/upload-artifact@v7
with:
path: jars/EssentialsXXMPP-*.jar
archive: false
+3 -10
View File
@@ -21,7 +21,6 @@ jobs:
steps:
- name: Mirror dump to a private Gist
id: mirror
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GIST_TOKEN }}
@@ -47,19 +46,13 @@ jobs:
public: false
});
core.setOutput('link', `${process.env.GIST_LINK_FMT}${gist.id}`);
core.setOutput('issue_number', issue.number);
const link = `${process.env.GIST_LINK_FMT}${gist.id}`;
- name: Comment gist link on issue
if: steps.mirror.outputs.link != ''
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ steps.mirror.outputs.issue_number }},
body: `📋 Essentials Dump Backup → ${{ steps.mirror.outputs.link }}`
issue_number: issue.number,
body: `📋 Essentials Dump Backup → ${link}`
});
cleanup-gist:
+2 -2
View File
@@ -11,8 +11,8 @@
</option>
<option name="locations">
<list>
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">bundled-sun-checks</ConfigurationLocation>
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">bundled-google-checks</ConfigurationLocation>
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="321e5753-4201-4d2c-bf31-6232011122fd" type="PROJECT_RELATIVE" scope="All" description="EssentialsX">
$PROJECT_DIR$/.checkstyle/checkstyle.xml
<option name="properties">
+3 -1
View File
@@ -3,7 +3,7 @@ plugins {
}
dependencies {
compileOnly('net.essentialsx.deps:VaultAPI:1.7') {
compileOnly('com.github.milkbowl:VaultAPI:1.7') {
exclude group: "org.bukkit", module: "bukkit"
}
compileOnly 'net.luckperms:api:5.3'
@@ -25,6 +25,7 @@ dependencies {
api(project(path: ':providers:PaperProvider', configuration: 'shadow')){
exclude(module: 'paper-api')
}
api project(':providers:FoliaProvider')
api(project(':providers:NMSReflectionProvider')) {
exclude(module: 'bukkit')
}
@@ -73,6 +74,7 @@ shadowJar {
include (dependency('net.kyori:adventure-text-minimessage'))
include (project(':providers:BaseProviders'))
include (project(path: ':providers:PaperProvider', configuration: 'shadow'))
include (project(':providers:FoliaProvider'))
include (project(':providers:NMSReflectionProvider'))
include (project(':providers:1_8Provider'))
include (project(':providers:1_12Provider'))
@@ -116,8 +116,6 @@ public class AlternativeCommandsHandler {
}
// return the first command that is not an alias
Command firstAlias = null;
final Iterator<WeakReference<Command>> iterator = commands.iterator();
while (iterator.hasNext()) {
final Command cmd = iterator.next().get();
@@ -129,14 +127,10 @@ public class AlternativeCommandsHandler {
if (cmd.getName().equalsIgnoreCase(label)) {
return cmd;
}
if (firstAlias == null) {
firstAlias = cmd;
}
}
// return the first alias, or null if every reference in this bucket has been collected
return firstAlias;
// return the first alias
return commands.get(0).get();
}
public void executed(final String label, final Command pc) {
@@ -139,19 +139,6 @@ public class AsyncTeleport implements IAsyncTeleport {
paperFuture.exceptionally(future::completeExceptionally);
}
private void runOnMain(final Runnable runnable) throws ExecutionException, InterruptedException {
if (Bukkit.isPrimaryThread()) {
runnable.run();
return;
}
final CompletableFuture<Object> taskLock = new CompletableFuture<>();
Bukkit.getScheduler().runTask(ess, () -> {
runnable.run();
taskLock.complete(new Object());
});
taskLock.get();
}
protected void nowAsync(final IUser teleportee, final ITarget target, final TeleportCause cause, final CompletableFuture<Boolean> future) {
cancel(false);
@@ -169,8 +156,8 @@ public class AsyncTeleport implements IAsyncTeleport {
}
try {
runOnMain(() -> teleportee.getBase().eject()); //EntityDismountEvent requires a sync context.
} catch (final ExecutionException | InterruptedException e) {
ess.ensureEntity(teleportee.getBase(), () -> teleportee.getBase().eject()); //EntityDismountEvent requires a sync context.
} catch (final RuntimeException e) {
future.completeExceptionally(e);
return;
}
@@ -190,8 +177,7 @@ public class AsyncTeleport implements IAsyncTeleport {
if (LocationUtil.isBlockUnsafeForUser(ess, teleportee, chunk.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) {
if (ess.getSettings().isTeleportSafetyEnabled()) {
if (ess.getSettings().isForceDisableTeleportSafety()) {
//The chunk we're teleporting to is 100% going to be loaded here, no need to teleport async.
teleportee.getBase().teleport(loc, cause);
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
} else {
try {
//There's a chance the safer location is outside the loaded chunk so still teleport async here.
@@ -207,8 +193,7 @@ public class AsyncTeleport implements IAsyncTeleport {
}
} else {
if (ess.getSettings().isForceDisableTeleportSafety()) {
//The chunk we're teleporting to is 100% going to be loaded here, no need to teleport async.
teleportee.getBase().teleport(loc, cause);
PaperLib.teleportAsync(teleportee.getBase(), loc, cause);
} else {
if (ess.getSettings().isTeleportToCenterLocation()) {
loc = LocationUtil.getRoundedDestination(loc);
@@ -1,13 +1,14 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import net.ess3.provider.SchedulingProvider;
import org.bukkit.Location;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import org.bukkit.Location;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import net.essentialsx.api.v2.events.TeleportWarmupCancelledEvent;
import net.essentialsx.api.v2.events.TeleportWarmupCancelledEvent.CancelReason;
@@ -31,7 +32,7 @@ public class AsyncTimedTeleport implements Runnable {
private final boolean timer_canMove;
private final Trade timer_chargeFor;
private final TeleportCause timer_cause;
private int timer_task;
private SchedulingProvider.EssentialsTask timer_task;
private double timer_health;
AsyncTimedTeleport(final IUser user, final IEssentials ess, final AsyncTeleport teleport, final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) {
@@ -55,7 +56,7 @@ public class AsyncTimedTeleport implements Runnable {
this.timer_respawn = respawn;
this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move");
timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId();
timer_task = ess.runTaskTimerAsynchronously(this, 20, 20);
if (future != null) {
this.parentFuture = future;
@@ -142,16 +143,16 @@ public class AsyncTimedTeleport implements Runnable {
}
}
ess.scheduleSyncDelayedTask(new DelayedTeleportTask());
ess.scheduleEntityDelayedTask(teleportOwner.getBase(), new DelayedTeleportTask());
}
//If we need to cancelTimer a pending teleportPlayer call this method
void cancelTimer(final boolean notifyUser) {
if (timer_task == -1) {
if (timer_task == null) {
return;
}
try {
ess.getServer().getScheduler().cancelTask(timer_task);
timer_task.cancel();
final IUser teleportUser = ess.getUser(this.timer_teleportee);
if (teleportUser != null && teleportUser.getBase() != null) {
@@ -167,7 +168,7 @@ public class AsyncTimedTeleport implements Runnable {
}
}
} finally {
timer_task = -1;
timer_task = null;
}
}
}
@@ -1,6 +1,7 @@
package com.earth2me.essentials;
import net.ess3.api.IEssentials;
import net.ess3.provider.SchedulingProvider;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
@@ -18,7 +19,7 @@ public class Backup implements Runnable {
private transient final IEssentials ess;
private final AtomicBoolean pendingShutdown = new AtomicBoolean(false);
private transient boolean running = false;
private transient int taskId = -1;
private transient SchedulingProvider.EssentialsTask task = null;
private transient boolean active = false;
private transient CompletableFuture<Object> taskLock = null;
@@ -36,10 +37,10 @@ public class Backup implements Runnable {
public synchronized void stopTask() {
running = false;
if (taskId != -1) {
server.getScheduler().cancelTask(taskId);
if (task != null) {
task.cancel();
}
taskId = -1;
task = null;
}
private synchronized void startTask() {
@@ -48,7 +49,7 @@ public class Backup implements Runnable {
if (interval < 1200) {
return;
}
taskId = ess.scheduleSyncRepeatingTask(this, interval, interval);
task = ess.scheduleGlobalRepeatingTask(this, interval, interval);
running = true;
}
}
@@ -123,7 +124,7 @@ public class Backup implements Runnable {
}
if (!pendingShutdown.get()) {
ess.scheduleSyncDelayedTask(new BackupEnableSaveTask());
ess.scheduleGlobalDelayedTask(new BackupEnableSaveTask());
}
}
});
@@ -13,11 +13,7 @@ import static com.earth2me.essentials.I18n.tlLiteral;
public final class Console implements IMessageRecipient {
public static final String NAME = "Console";
public static String displayName() {
return tlLiteral("consoleName");
}
public static final String DISPLAY_NAME = tlLiteral("consoleName");
private static Console instance; // Set in essentials
private final IEssentials ess;
@@ -60,7 +56,7 @@ public final class Console implements IMessageRecipient {
@Override
public String getDisplayName() {
return displayName();
return Console.DISPLAY_NAME;
}
@Override
@@ -17,13 +17,13 @@ public final class Enchantments {
static {
final Enchantment SHARPNESS = RegistryUtil.valueOf(Enchantment.class, "DAMAGE_ALL", "SHARPNESS");
ENCHANTMENTS.put("alldamage", SHARPNESS);
ALIASENCHANTMENTS.put("alldmg", SHARPNESS);
ENCHANTMENTS.put("sharpness", SHARPNESS);
ALIASENCHANTMENTS.put("sharp", SHARPNESS);
ALIASENCHANTMENTS.put("dal", SHARPNESS);
final Enchantment BANE_OF_ARTHROPODS = RegistryUtil.valueOf(Enchantment.class, "DAMAGE_ARTHROPODS", "BANE_OF_ARTHROPODS");
ENCHANTMENTS.put("ardmg", BANE_OF_ARTHROPODS);
@@ -31,13 +31,13 @@ public final class Enchantments {
ALIASENCHANTMENTS.put("baneofarthropod", BANE_OF_ARTHROPODS);
ALIASENCHANTMENTS.put("arthropod", BANE_OF_ARTHROPODS);
ALIASENCHANTMENTS.put("dar", BANE_OF_ARTHROPODS);
final Enchantment SMITE = RegistryUtil.valueOf(Enchantment.class, "DAMAGE_UNDEAD", "SMITE");
ENCHANTMENTS.put("undeaddamage", SMITE);
ENCHANTMENTS.put("smite", SMITE);
ALIASENCHANTMENTS.put("du", SMITE);
final Enchantment EFFICIENCY = RegistryUtil.valueOf(Enchantment.class, "DIG_SPEED", "EFFICIENCY");
ENCHANTMENTS.put("digspeed", EFFICIENCY);
@@ -46,7 +46,7 @@ public final class Enchantments {
ALIASENCHANTMENTS.put("cutspeed", EFFICIENCY);
ALIASENCHANTMENTS.put("ds", EFFICIENCY);
ALIASENCHANTMENTS.put("eff", EFFICIENCY);
final Enchantment UNBREAKING = RegistryUtil.valueOf(Enchantment.class, "DURABILITY", "UNBREAKING");
ENCHANTMENTS.put("durability", UNBREAKING);
@@ -70,21 +70,21 @@ public final class Enchantments {
ALIASENCHANTMENTS.put("kback", Enchantment.KNOCKBACK);
ALIASENCHANTMENTS.put("kb", Enchantment.KNOCKBACK);
ALIASENCHANTMENTS.put("k", Enchantment.KNOCKBACK);
final Enchantment FORTUNE = RegistryUtil.valueOf(Enchantment.class, "LOOT_BONUS_BLOCKS", "FORTUNE");
ALIASENCHANTMENTS.put("blockslootbonus", FORTUNE);
ENCHANTMENTS.put("fortune", FORTUNE);
ALIASENCHANTMENTS.put("fort", FORTUNE);
ALIASENCHANTMENTS.put("lbb", FORTUNE);
final Enchantment LOOTING = RegistryUtil.valueOf(Enchantment.class, "LOOT_BONUS_MOBS", "LOOTING");
ALIASENCHANTMENTS.put("mobslootbonus", LOOTING);
ENCHANTMENTS.put("mobloot", LOOTING);
ENCHANTMENTS.put("looting", LOOTING);
ALIASENCHANTMENTS.put("lbm", LOOTING);
final Enchantment RESPIRATION = RegistryUtil.valueOf(Enchantment.class, "OXYGEN", "RESPIRATION");
ALIASENCHANTMENTS.put("oxygen", RESPIRATION);
@@ -92,14 +92,14 @@ public final class Enchantments {
ALIASENCHANTMENTS.put("breathing", RESPIRATION);
ENCHANTMENTS.put("breath", RESPIRATION);
ALIASENCHANTMENTS.put("o", RESPIRATION);
final Enchantment PROTECTION = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_ENVIRONMENTAL", "PROTECTION");
ENCHANTMENTS.put("protection", PROTECTION);
ALIASENCHANTMENTS.put("prot", PROTECTION);
ENCHANTMENTS.put("protect", PROTECTION);
ALIASENCHANTMENTS.put("p", PROTECTION);
final Enchantment BLAST_PROTECTION = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_EXPLOSIONS", "BLAST_PROTECTION");
ALIASENCHANTMENTS.put("explosionsprotection", BLAST_PROTECTION);
@@ -110,7 +110,7 @@ public final class Enchantments {
ALIASENCHANTMENTS.put("bprotect", BLAST_PROTECTION);
ENCHANTMENTS.put("blastprotect", BLAST_PROTECTION);
ALIASENCHANTMENTS.put("pe", BLAST_PROTECTION);
final Enchantment FEATHER_FALLING = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_FALL", "FEATHER_FALLING");
ALIASENCHANTMENTS.put("fallprotection", FEATHER_FALLING);
@@ -118,7 +118,7 @@ public final class Enchantments {
ENCHANTMENTS.put("featherfall", FEATHER_FALLING);
ALIASENCHANTMENTS.put("featherfalling", FEATHER_FALLING);
ALIASENCHANTMENTS.put("pfa", FEATHER_FALLING);
final Enchantment FIRE_PROTECTION = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_FIRE", "FIRE_PROTECTION");
ALIASENCHANTMENTS.put("fireprotection", FIRE_PROTECTION);
@@ -128,7 +128,7 @@ public final class Enchantments {
ENCHANTMENTS.put("fireprot", FIRE_PROTECTION);
ALIASENCHANTMENTS.put("flameprot", FIRE_PROTECTION);
ALIASENCHANTMENTS.put("pf", FIRE_PROTECTION);
final Enchantment PROJECTILE_PROTECTION = RegistryUtil.valueOf(Enchantment.class, "PROTECTION_PROJECTILE", "PROJECTILE_PROTECTION");
ENCHANTMENTS.put("projectileprotection", PROJECTILE_PROTECTION);
@@ -138,28 +138,28 @@ public final class Enchantments {
ENCHANTMENTS.put("silktouch", Enchantment.SILK_TOUCH);
ALIASENCHANTMENTS.put("softtouch", Enchantment.SILK_TOUCH);
ALIASENCHANTMENTS.put("st", Enchantment.SILK_TOUCH);
final Enchantment AQUA_AFFINITY = RegistryUtil.valueOf(Enchantment.class, "WATER_WORKER", "AQUA_AFFINITY");
ENCHANTMENTS.put("waterworker", AQUA_AFFINITY);
ENCHANTMENTS.put("aquaaffinity", AQUA_AFFINITY);
ALIASENCHANTMENTS.put("watermine", AQUA_AFFINITY);
ALIASENCHANTMENTS.put("ww", AQUA_AFFINITY);
final Enchantment FLAME = RegistryUtil.valueOf(Enchantment.class, "ARROW_FIRE", "FLAME");
ALIASENCHANTMENTS.put("firearrow", FLAME);
ENCHANTMENTS.put("flame", FLAME);
ENCHANTMENTS.put("flamearrow", FLAME);
ALIASENCHANTMENTS.put("af", FLAME);
final Enchantment POWER = RegistryUtil.valueOf(Enchantment.class, "ARROW_DAMAGE", "POWER");
ENCHANTMENTS.put("arrowdamage", POWER);
ENCHANTMENTS.put("power", POWER);
ALIASENCHANTMENTS.put("arrowpower", POWER);
ALIASENCHANTMENTS.put("ad", POWER);
final Enchantment PUNCH = RegistryUtil.valueOf(Enchantment.class, "ARROW_KNOCKBACK", "PUNCH");
ENCHANTMENTS.put("arrowknockback", PUNCH);
@@ -167,7 +167,7 @@ public final class Enchantments {
ENCHANTMENTS.put("punch", PUNCH);
ALIASENCHANTMENTS.put("arrowpunch", PUNCH);
ALIASENCHANTMENTS.put("ak", PUNCH);
final Enchantment INFINITY = RegistryUtil.valueOf(Enchantment.class, "ARROW_INFINITE", "INFINITY");
ALIASENCHANTMENTS.put("infinitearrows", INFINITY);
@@ -177,7 +177,7 @@ public final class Enchantments {
ALIASENCHANTMENTS.put("unlimited", INFINITY);
ALIASENCHANTMENTS.put("unlimitedarrows", INFINITY);
ALIASENCHANTMENTS.put("ai", INFINITY);
final Enchantment LUCK_OF_THE_SEA = RegistryUtil.valueOf(Enchantment.class, "LUCK", "LUCK_OF_THE_SEA");
ENCHANTMENTS.put("luck", LUCK_OF_THE_SEA);
@@ -313,7 +313,7 @@ public final class Enchantments {
ENCHANTMENTS.put("density", density);
}
final Enchantment windBurst = Enchantment.getByName("WIND_BURST");
if (windBurst != null) {
if (breach != null) {
ENCHANTMENTS.put("windburst", windBurst);
ALIASENCHANTMENTS.put("wind", windBurst);
ALIASENCHANTMENTS.put("burst", windBurst);
@@ -321,14 +321,6 @@ public final class Enchantments {
} catch (final IllegalArgumentException ignored) {
}
try { // 1.21.11
final Enchantment lunge = Enchantment.getByName("LUNGE");
if (lunge != null) {
ENCHANTMENTS.put("lunge", lunge);
}
} catch (final IllegalArgumentException ignored) {
}
try {
final Class<?> namespacedKeyClass = Class.forName("org.bukkit.NamespacedKey");
final Class<?> enchantmentClass = Class.forName("org.bukkit.enchantments.Enchantment");
@@ -28,6 +28,7 @@ import com.earth2me.essentials.commands.NoChargeException;
import com.earth2me.essentials.commands.NotEnoughArgumentsException;
import com.earth2me.essentials.commands.PlayerNotFoundException;
import com.earth2me.essentials.commands.QuietAbortException;
import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.economy.EconomyLayers;
import com.earth2me.essentials.economy.vault.VaultEconomyProvider;
import com.earth2me.essentials.items.AbstractItemDb;
@@ -46,12 +47,9 @@ import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.updatecheck.UpdateChecker;
import com.earth2me.essentials.userstorage.ModernUserMap;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.ModernPaperEnvironment;
import com.earth2me.essentials.utils.PasteUtil;
import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib;
import net.ess3.api.Economy;
import com.earth2me.essentials.config.EssentialsConfiguration;
import net.ess3.api.IEssentials;
import net.ess3.api.IItemDb;
import net.ess3.api.IJails;
@@ -70,19 +68,21 @@ import net.ess3.provider.InventoryViewProvider;
import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.PlayerLocaleProvider;
import net.ess3.provider.ProviderListener;
import net.ess3.provider.SchedulingProvider;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.providers.BaseBannerDataProvider;
import net.ess3.provider.providers.BaseInventoryViewProvider;
import net.ess3.provider.providers.BlockMetaSpawnerItemProvider;
import net.ess3.provider.providers.BukkitMaterialTagProvider;
import net.ess3.provider.providers.BukkitSchedulingProvider;
import net.ess3.provider.providers.BukkitSpawnerBlockProvider;
import net.ess3.provider.providers.BukkitTileEntityProvider;
import net.ess3.provider.providers.BukkitWorldTileEntityCountProvider;
import net.ess3.provider.providers.FixedHeightWorldInfoProvider;
import net.ess3.provider.providers.FlatSpawnEggProvider;
import net.ess3.provider.providers.FoliaSchedulingProvider;
import net.ess3.provider.providers.LegacyBannerDataProvider;
import net.ess3.provider.providers.LegacyBiomeNameProvider;
import net.ess3.provider.providers.LegacyPatternTypeProvider;
import net.ess3.provider.providers.ModernPatternTypeProvider;
import net.ess3.provider.providers.LegacyDamageEventProvider;
import net.ess3.provider.providers.LegacyInventoryViewProvider;
import net.ess3.provider.providers.LegacyItemUnbreakableProvider;
@@ -106,10 +106,12 @@ import net.ess3.provider.providers.PaperSerializationProvider;
import net.ess3.provider.providers.PaperServerStateProvider;
import net.ess3.provider.providers.PaperTickCountProvider;
import net.ess3.provider.providers.PaperTileEntityProvider;
import net.ess3.provider.providers.PaperWorldTileEntityCountProvider;
import net.ess3.provider.providers.PrehistoricPotionMetaProvider;
import net.essentialsx.api.v2.services.BalanceTop;
import net.essentialsx.api.v2.services.mail.MailService;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.Block;
@@ -119,6 +121,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
@@ -133,8 +136,6 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import java.util.ArrayList;
import java.util.Collection;
@@ -147,11 +148,11 @@ import java.util.Map;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tlLiteral;
import static com.earth2me.essentials.I18n.tlLocale;
@@ -262,10 +263,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
getLogger().severe(getAdventureFacet().miniToLegacy(tlLiteral("serverSnapshot")));
}
if (PaperLib.isPaper() && !PaperLib.isVersion(13) && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) {
PaperLib.setCustomEnvironment(new ModernPaperEnvironment());
}
final PluginManager pm = getServer().getPluginManager();
for (final Plugin plugin : pm.getPlugins()) {
if (plugin.getDescription().getName().startsWith("Essentials") && !plugin.getDescription().getVersion().equals(this.getDescription().getVersion()) && !plugin.getDescription().getName().equals("EssentialsAntiCheat")) {
@@ -332,9 +329,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
confList.add(jails);
execTimer.mark("Init(Jails)");
EconomyLayers.onEnable(this);
execTimer.mark("Init(EconomyLayers)");
// Spawner item provider only uses one, but it's here for legacy...
providerFactory.registerProvider(BlockMetaSpawnerItemProvider.class);
@@ -350,9 +344,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
//Banner Meta Provider
providerFactory.registerProvider(LegacyBannerDataProvider.class, BaseBannerDataProvider.class);
// Pattern Type Provider
providerFactory.registerProvider(LegacyPatternTypeProvider.class, ModernPatternTypeProvider.class);
// Server State Provider
providerFactory.registerProvider(ReflServerStateProvider.class, PaperServerStateProvider.class);
@@ -407,10 +398,16 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
// Tile Entity Provider
providerFactory.registerProvider(BukkitTileEntityProvider.class, PaperTileEntityProvider.class);
// World Tile Entity Count Provider
providerFactory.registerProvider(BukkitWorldTileEntityCountProvider.class, PaperWorldTileEntityCountProvider.class);
// Tick Count Provider
providerFactory.registerProvider(PaperTickCountProvider.class);
if (!TESTING) {
// Scheduling provider
providerFactory.registerProvider(FoliaSchedulingProvider.class, BukkitSchedulingProvider.class);
if (!TESTING || true) { // FIXME: The scheduling provider is necessary for tests to pass without adding checks for TESTING everywhere
providerFactory.finalizeRegistration();
}
@@ -431,6 +428,12 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
execTimer.mark("Init(Providers)");
EconomyLayers.onEnable(this);
execTimer.mark("Init(EconomyLayers)");
registerListeners(getServer().getPluginManager());
initAdventureFacet();
reload();
// The item spawn blacklist is loaded with all other settings, before the item
@@ -441,7 +444,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
alternativeCommandsHandler = new AlternativeCommandsHandler(this);
timer = new EssentialsTimer(this);
scheduleSyncRepeatingTask(timer, 1000, 50);
scheduleGlobalRepeatingTask(timer, 1000, 50);
Economy.setEss(this);
execTimer.mark("RegHandler");
@@ -494,8 +497,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
private void registerListeners(final PluginManager pm) {
HandlerList.unregisterAll(this);
if (getSettings().isDebug()) {
LOGGER.log(Level.INFO, "Registering Listeners");
}
@@ -593,8 +594,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
getUsers().shutdown();
EssentialsConfiguration.shutdownExecutor();
PasteUtil.shutdownExecutor();
getServer().getScheduler().cancelTasks(this);
HandlerList.unregisterAll(this);
}
@@ -617,9 +616,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
}
final PluginManager pm = getServer().getPluginManager();
registerListeners(pm);
initAdventureFacet();
}
@@ -628,9 +624,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
adventureFacet.close();
}
// Paper only started bundling a modern enough native Adventure (with the MiniMessage TagResolver API)
// in 1.18.2, so older versions must continue using our bundled Adventure via the Spigot facet.
if (VersionUtil.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_18_2_R01)) {
if (VersionUtil.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_16_5_R01)) {
adventureFacet = new PaperAdventureFacet(getSettings() != null ? getSettings().getPrimaryColor() : null, getSettings() != null ? getSettings().getSecondaryColor() : null);
} else {
adventureFacet = new SpigotAdventureFacet(this);
@@ -854,7 +848,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
sender.sendTl("commandHelpLine2", description);
sender.sendTl("commandHelpLine3");
for (Map.Entry<String, String> usage : cmd.getUsageStrings().entrySet()) {
sender.sendTl("commandHelpLineUsage", AdventureUtil.parsed(usage.getKey().replace("<command>", commandLabel)), AdventureUtil.parsed(sender.tl(usage.getValue())));
sender.sendTl("commandHelpLineUsage", AdventureUtil.parsed(usage.getKey().replace("<command>", commandLabel)), AdventureUtil.parsed(usage.getValue()));
}
} else {
sender.sendMessage(command.getDescription());
@@ -915,16 +909,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
}
@Override
public BukkitScheduler getScheduler() {
return this.getServer().getScheduler();
}
@Override
public List<Player> getJailedPlayers() {
return getUsers().getAllUserUUIDs().stream().map(this::getUser).filter(Objects::nonNull).filter(User::isJailed).map(User::getBase).filter(Objects::nonNull).collect(Collectors.toList());
}
@Override
public IJails getJails() {
return jails;
@@ -1248,33 +1232,135 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
}
@Override
public BukkitTask runTaskAsynchronously(final Runnable run) {
return this.getScheduler().runTaskAsynchronously(this, run);
public void scheduleInitTask(Runnable runnable) {
provider(SchedulingProvider.class).registerInitTask(runnable);
}
@Override
public BukkitTask runTaskLaterAsynchronously(final Runnable run, final long delay) {
return this.getScheduler().runTaskLaterAsynchronously(this, run, delay);
public void runTaskAsynchronously(final Runnable run) {
provider(SchedulingProvider.class).runAsyncTask(run);
}
@Override
public BukkitTask runTaskTimerAsynchronously(final Runnable run, final long delay, final long period) {
return this.getScheduler().runTaskTimerAsynchronously(this, run, delay, period);
public void runTaskLaterAsynchronously(final Runnable run, final long delay) {
provider(SchedulingProvider.class).runAsyncTaskLater(run, delay);
}
@Override
public int scheduleSyncDelayedTask(final Runnable run) {
return this.getScheduler().scheduleSyncDelayedTask(this, run);
public SchedulingProvider.EssentialsTask runTaskTimerAsynchronously(final Runnable run, final long delay, final long period) {
return provider(SchedulingProvider.class).runAsyncTaskRepeating(run, delay, period);
}
@Override
public int scheduleSyncDelayedTask(final Runnable run, final long delay) {
return this.getScheduler().scheduleSyncDelayedTask(this, run, delay);
public void scheduleEntityDelayedTask(Entity entity, Runnable run) {
provider(SchedulingProvider.class).runEntityTask(entity, run);
}
@Override
public int scheduleSyncRepeatingTask(final Runnable run, final long delay, final long period) {
return this.getScheduler().scheduleSyncRepeatingTask(this, run, delay, period);
public SchedulingProvider.EssentialsTask scheduleEntityDelayedTask(Entity entity, Runnable run, long delay) {
return provider(SchedulingProvider.class).runEntityTask(entity, run, delay);
}
@Override
public SchedulingProvider.EssentialsTask scheduleEntityRepeatingTask(Entity entity, Runnable run, long delay, long period) {
return provider(SchedulingProvider.class).runEntityTaskRepeating(entity, run, delay, period);
}
@Override
public void scheduleLocationDelayedTask(Location location, Runnable run) {
provider(SchedulingProvider.class).runLocationalTask(location, run);
}
@Override
public void scheduleLocationDelayedTask(Location location, Runnable run, long delay) {
provider(SchedulingProvider.class).runLocationalTask(location, run, delay);
}
@Override
public SchedulingProvider.EssentialsTask scheduleLocationRepeatingTask(Location location, Runnable run, long delay, long period) {
return provider(SchedulingProvider.class).runLocationalTaskRepeating(location, run, delay, period);
}
@Override
public void scheduleGlobalDelayedTask(Runnable run, long delay) {
provider(SchedulingProvider.class).runGlobalLocationalTask(run, delay);
}
@Override
public SchedulingProvider.EssentialsTask scheduleGlobalRepeatingTask(Runnable run, long delay, long period) {
return provider(SchedulingProvider.class).runGlobalLocationalTaskRepeating(run, delay, period);
}
@Override
public boolean isEntityThread(Entity entity) {
return provider(SchedulingProvider.class).isEntityThread(entity);
}
@Override
public boolean isRegionThread(Location location) {
return provider(SchedulingProvider.class).isRegionThread(location);
}
@Override
public boolean isGlobalThread() {
return provider(SchedulingProvider.class).isGlobalThread();
}
@Override
public void ensureEntity(Entity entity, Runnable runnable) {
if (isEntityThread(entity)) {
runnable.run();
return;
}
final CompletableFuture<Object> taskLock = new CompletableFuture<>();
scheduleEntityDelayedTask(entity, () -> {
runnable.run();
taskLock.complete(new Object());
});
try {
taskLock.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public void ensureRegion(Location location, Runnable runnable) {
if (isRegionThread(location)) {
runnable.run();
return;
}
final CompletableFuture<Object> taskLock = new CompletableFuture<>();
scheduleLocationDelayedTask(location, () -> {
runnable.run();
taskLock.complete(new Object());
});
try {
taskLock.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public void ensureGlobal(Runnable runnable) {
if (isGlobalThread()) {
runnable.run();
return;
}
final CompletableFuture<Object> taskLock = new CompletableFuture<>();
scheduleGlobalDelayedTask(() -> {
runnable.run();
taskLock.complete(new Object());
});
try {
taskLock.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
@@ -44,7 +44,7 @@ public class EssentialsBlockListener implements Listener {
final User user = ess.getUser(event.getPlayer());
if (user.hasUnlimited(is) && user.getBase().getGameMode() == GameMode.SURVIVAL) {
ess.scheduleSyncDelayedTask(() -> {
ess.scheduleEntityDelayedTask(user.getBase(), () -> {
if (is != null && is.getType() != null && !MaterialUtil.isAir(is.getType())) {
final ItemStack cloneIs = is.clone();
cloneIs.setAmount(1);
@@ -110,7 +110,7 @@ public class EssentialsEntityListener implements Listener {
}
}
ess.scheduleSyncDelayedTask(new PowerToolInteractTask());
ess.scheduleEntityDelayedTask(attacker.getBase(), new PowerToolInteractTask());
event.setCancelled(true);
return;
@@ -22,6 +22,7 @@ import io.papermc.paper.event.player.PlayerServerFullCheckEvent;
import net.ess3.api.IEssentials;
import net.ess3.api.events.AfkStatusChangeEvent;
import net.ess3.provider.CommandSendListenerProvider;
import net.ess3.provider.SchedulingProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.InventoryViewProvider;
import net.ess3.provider.KnownCommandsProvider;
@@ -94,7 +95,7 @@ import static com.earth2me.essentials.I18n.tlLiteral;
public class EssentialsPlayerListener implements Listener {
private final transient IEssentials ess;
private final ConcurrentHashMap<UUID, Integer> pendingMotdTasks = new ConcurrentHashMap<>();
private final ConcurrentHashMap<UUID, SchedulingProvider.EssentialsTask> pendingMotdTasks = new ConcurrentHashMap<>();
public EssentialsPlayerListener(final IEssentials parent) {
this.ess = parent;
@@ -193,7 +194,22 @@ public class EssentialsPlayerListener implements Listener {
final User user = ess.getUser(event.getPlayer());
if (user.isMuted()) {
event.setCancelled(true);
user.notifyMuted();
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
if (user.hasMuteReason()) {
user.sendTl("voiceSilencedReason", user.getMuteReason());
} else {
user.sendTl("voiceSilenced");
}
} else {
if (user.hasMuteReason()) {
user.sendTl("voiceSilencedReasonTime", dateDiff, user.getMuteReason());
} else {
user.sendTl("voiceSilencedTime", dateDiff);
}
}
ess.getLogger().info(ess.getAdventureFacet().miniToLegacy(tlLiteral("mutedUserSpeaks", user.getName(), event.getMessage())));
}
try {
@@ -274,9 +290,9 @@ public class EssentialsPlayerListener implements Listener {
public void onPlayerQuit(final PlayerQuitEvent event) {
final User user = ess.getUser(event.getPlayer());
final Integer pendingId = pendingMotdTasks.remove(user.getUUID());
if (pendingId != null) {
ess.getScheduler().cancelTask(pendingId);
final SchedulingProvider.EssentialsTask pendingTask = pendingMotdTasks.remove(user.getUUID());
if (pendingTask != null) {
pendingTask.cancel();
}
if (hideJoinQuitMessages() || ess.getSettings().allowSilentJoinQuit() && user.isAuthorized("essentials.silentquit")) {
@@ -405,25 +421,14 @@ public class EssentialsPlayerListener implements Listener {
final String lastAccountName = user.getLastAccountName(); // For comparison
user.setLastAccountName(user.getBase().getName());
final boolean newUsername = lastAccountName != null && !lastAccountName.equals(user.getBase().getName());
// A null last account name means EssentialsX has never recorded this player before, i.e. it's their first join.
// We rely on EssentialsX's own user data here rather than Player#hasPlayedBefore(), which is unreliable on modern
// server platforms that persist player data during the login/configuration phase.
// See https://github.com/EssentialsX/Essentials/issues/6466, https://github.com/EssentialsX/Essentials/issues/6464
final boolean firstJoin = lastAccountName == null;
// If the Minecraft account name changed, reset the nickname so the old one doesn't persist
if (ess.getSettings().isResetNickOnNameChange() && newUsername && user.getNickname() != null) {
user.setNickname(null);
}
user.setLastLogin(currentTime);
user.setDisplayNick();
updateCompass(user);
user.setLeavingHidden(false);
// Check for new username. If they don't want the message, let's just say it's false.
final boolean newUsername = ess.getSettings().isCustomNewUsernameMessage() && lastAccountName != null && !lastAccountName.equals(user.getBase().getName());
if (!ess.getVanishedPlayersNew().isEmpty() && !user.isAuthorized("essentials.vanish.see")) {
for (final String p : ess.getVanishedPlayersNew()) {
final Player toVanish = ess.getServer().getPlayerExact(p);
@@ -449,7 +454,7 @@ public class EssentialsPlayerListener implements Listener {
} else if (message == null || hideJoinQuitMessages()) {
effectiveMessage = null;
} else if (ess.getSettings().isCustomJoinMessage()) {
final String msg = (newUsername && ess.getSettings().isCustomNewUsernameMessage() ? ess.getSettings().getCustomNewUsernameMessage() : ess.getSettings().getCustomJoinMessage())
final String msg = (newUsername ? ess.getSettings().getCustomNewUsernameMessage() : ess.getSettings().getCustomJoinMessage())
.replace("{PLAYER}", user.getDisplayName()).replace("{USERNAME}", user.getName())
.replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUsers().getUserCount()))
.replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size()))
@@ -469,13 +474,13 @@ public class EssentialsPlayerListener implements Listener {
joinMessageConsumer.accept(effectiveMessage);
}
ess.runTaskAsynchronously(() -> ess.getServer().getPluginManager().callEvent(new AsyncUserDataLoadEvent(user, effectiveMessage, firstJoin)));
ess.runTaskAsynchronously(() -> ess.getServer().getPluginManager().callEvent(new AsyncUserDataLoadEvent(user, effectiveMessage)));
if (ess.getSettings().getMotdDelay() >= 0) {
final int motdDelay = ess.getSettings().getMotdDelay() / 50;
final Runnable motdTask = () -> motdFlow(user);
if (motdDelay > 0) {
pendingMotdTasks.put(user.getUUID(), ess.scheduleSyncDelayedTask(motdTask, motdDelay));
pendingMotdTasks.put(user.getUUID(), ess.scheduleEntityDelayedTask(user.getBase(), motdTask, motdDelay));
} else {
motdTask.run();
}
@@ -499,21 +504,12 @@ public class EssentialsPlayerListener implements Listener {
});
}
final boolean restoreFly = user.isFlyModeEnabled() && user.isAuthorized("essentials.fly");
if (restoreFly) {
user.getBase().setAllowFlight(true);
if (ess.getSettings().isSendFlyEnableOnJoin()) {
user.sendTl("flyMode", CommonPlaceholders.enableDisable(user.getSource(), true), user.getDisplayName());
}
}
if (user.isAuthorized("essentials.fly.safelogin")) {
user.getBase().setFallDistance(0);
final boolean inWater = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_17_R01) && user.getBase().isInWater();
if (!inWater && LocationUtil.shouldFly(ess, user.getLocation())) {
if (LocationUtil.shouldFly(ess, user.getLocation())) {
user.getBase().setAllowFlight(true);
user.getBase().setFlying(true);
if (!restoreFly && ess.getSettings().isSendFlyEnableOnJoin()) {
if (ess.getSettings().isSendFlyEnableOnJoin()) {
user.sendTl("flyMode", CommonPlaceholders.enableDisable(user.getSource(), true), user.getDisplayName());
}
}
@@ -529,11 +525,6 @@ public class EssentialsPlayerListener implements Listener {
ess.getLogger().log(Level.INFO, "Set socialspy to false for {0} because they had it enabled without permission.", user.getName());
}
if (user.isFlyModeEnabled() && !user.isAuthorized("essentials.fly")) {
user.setFlyModeEnabled(false);
ess.getLogger().log(Level.INFO, "Set fly mode to false for {0} because they had it enabled without permission.", user.getName());
}
if (user.isGodModeEnabled() && !user.isAuthorized("essentials.god")) {
user.setGodModeEnabled(false);
ess.getLogger().log(Level.INFO, "Set god mode to false for {0} because they had it enabled without permission.", user.getName());
@@ -591,7 +582,7 @@ public class EssentialsPlayerListener implements Listener {
dUser.updateActivity(false, AfkStatusChangeEvent.Cause.JOIN);
dUser.stopTransaction();
ess.scheduleSyncDelayedTask(() -> {
ess.scheduleEntityDelayedTask(player, () -> {
final User user = ess.getUser(player);
if (!user.getBase().isOnline()) {
@@ -761,7 +752,7 @@ public class EssentialsPlayerListener implements Listener {
final User user = ess.getUser(event.getPlayer());
if (user.hasUnlimited(new ItemStack(event.getBucket()))) {
event.getItemStack().setType(event.getBucket());
ess.scheduleSyncDelayedTask(user.getBase()::updateInventory);
ess.scheduleEntityDelayedTask(user.getBase(), user.getBase()::updateInventory);
}
}
@@ -804,9 +795,10 @@ public class EssentialsPlayerListener implements Listener {
final ComponentHolder base = (user.isMuted() && ess.getSettings().getSocialSpyListenMutedPlayers())
? spyer.tlComponent("socialSpyMutedPrefix")
: spyer.tlComponent("socialSpyPrefix");
final ComponentHolder formatted = ess.getAdventureFacet().deserializeMiniMessage(spyer.playerTl("socialSpyCmdFormat", playerName, event.getMessage()));
final ComponentHolder nameComponent = ess.getAdventureFacet().legacyToAdventure(playerName);
final ComponentHolder messageComponent = ess.getAdventureFacet().text(": " + event.getMessage());
spyer.sendComponent(ess.getAdventureFacet().append(base, formatted));
spyer.sendComponent(ess.getAdventureFacet().append(base, nameComponent, messageComponent));
}
}
}
@@ -816,7 +808,20 @@ public class EssentialsPlayerListener implements Listener {
final User user = ess.getUser(player);
if (user.isMuted() && (ess.getSettings().getMuteCommands().contains(cmd) || ess.getSettings().getMuteCommands().contains("*"))) {
event.setCancelled(true);
user.notifyMuted();
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
if (user.hasMuteReason()) {
user.sendTl("voiceSilencedReason", user.getMuteReason());
} else {
user.sendTl("voiceSilenced");
}
} else {
if (user.hasMuteReason()) {
user.sendTl("voiceSilencedReasonTime", dateDiff, user.getMuteReason());
} else {
user.sendTl("voiceSilencedTime", dateDiff);
}
}
ess.getLogger().info(ess.getAdventureFacet().miniToLegacy(tlLiteral("mutedUserSpeaks", player.getName(), event.getMessage())));
return;
}
@@ -1008,7 +1013,7 @@ public class EssentialsPlayerListener implements Listener {
}
}
ess.scheduleSyncDelayedTask(new DelayedClickJumpTask());
ess.scheduleEntityDelayedTask(user.getBase(), new DelayedClickJumpTask());
} catch (final Exception ex) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.WARNING, ex.getMessage(), ex);
@@ -1039,7 +1044,7 @@ public class EssentialsPlayerListener implements Listener {
}
}
ess.scheduleSyncDelayedTask(new PowerToolUseTask());
ess.scheduleEntityDelayedTask(user.getBase(), new PowerToolUseTask());
}
}
@@ -1101,7 +1106,7 @@ public class EssentialsPlayerListener implements Listener {
}
if (refreshPlayer != null) {
ess.scheduleSyncDelayedTask(refreshPlayer::updateInventory, 1);
ess.scheduleEntityDelayedTask(refreshPlayer, refreshPlayer::updateInventory, 1);
}
}
@@ -1164,16 +1169,12 @@ public class EssentialsPlayerListener implements Listener {
}
if (refreshPlayer != null) {
ess.scheduleSyncDelayedTask(refreshPlayer::updateInventory, 1);
ess.scheduleEntityDelayedTask(refreshPlayer, refreshPlayer::updateInventory, 1);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerFishEvent(final PlayerFishEvent event) {
if (!ess.getSettings().cancelAfkOnFish()) {
return;
}
final User user = ess.getUser(event.getPlayer());
user.updateActivityOnInteract(true);
}
@@ -1192,7 +1193,7 @@ public class EssentialsPlayerListener implements Listener {
final Player player = event.getPlayer();
if (player.isFlying() && player.getAllowFlight() && user.isAuthorized("essentials.fly")) {
// The gamemode change happens after the event, so we need to delay the flight enable
ess.scheduleSyncDelayedTask(() -> {
ess.scheduleEntityDelayedTask(player, () -> {
player.setAllowFlight(true);
player.setFlying(true);
}, 1);
@@ -1213,12 +1214,10 @@ public class EssentialsPlayerListener implements Listener {
public void onPlayerPickupItem(final org.bukkit.event.player.PlayerPickupItemEvent event) {
if (event.getItem().hasMetadata(Commandfireball.FIREBALL_META_KEY)) {
event.setCancelled(true);
return;
}
final User user = ess.getUser(event.getPlayer());
if ((ess.getSettings().getDisableItemPickupWhileAfk() && user.isAfk())
|| (user.isVanished() && !user.isAuthorizedCached("essentials.vanish.pickup"))) {
event.setCancelled(true);
} else if (ess.getSettings().getDisableItemPickupWhileAfk()) {
if (ess.getUser(event.getPlayer()).isAfk()) {
event.setCancelled(true);
}
}
}
}
@@ -1226,10 +1225,8 @@ public class EssentialsPlayerListener implements Listener {
private final class PickupListener1_12 implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerPickupItem(final org.bukkit.event.entity.EntityPickupItemEvent event) {
if (event.getEntity() instanceof Player) {
final User user = ess.getUser((Player) event.getEntity());
if ((ess.getSettings().getDisableItemPickupWhileAfk() && user.isAfk())
|| (user.isVanished() && !user.isAuthorizedCached("essentials.vanish.pickup"))) {
if (ess.getSettings().getDisableItemPickupWhileAfk() && event.getEntity() instanceof Player) {
if (ess.getUser((Player) event.getEntity()).isAfk()) {
event.setCancelled(true);
}
}
@@ -1248,10 +1245,6 @@ public class EssentialsPlayerListener implements Listener {
private final class CommandSendFilter implements CommandSendListenerProvider.Filter {
@Override
public Predicate<String> apply(Player player) {
// There is no event for op status changes, but the command list is resent when
// a player is opped/deopped, so we invalidate cached permissions here.
ess.getPermissionsHandler().invalidatePermissionCache(player.getUniqueId());
final User user = ess.getUser(player);
final Set<PluginCommand> checked = new HashSet<>();
final Set<PluginCommand> toRemove = new HashSet<>();
@@ -5,7 +5,6 @@ import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
@@ -13,36 +12,19 @@ import java.util.logging.Level;
public class EssentialsTimer implements Runnable {
private final transient IEssentials ess;
private final transient Set<UUID> onlineUsers = new HashSet<>(); // Field is necessary for hidden users
private final LinkedList<Double> history = new LinkedList<>();
@SuppressWarnings("FieldCanBeLocal")
private final long maxTime = 10 * 1000000;
@SuppressWarnings("FieldCanBeLocal")
private final long tickInterval = 50;
private transient long lastPoll = System.nanoTime();
private static final long maxTime = 10 * 1000000;
private int skip1 = 0;
private int skip2 = 0;
EssentialsTimer(final IEssentials ess) {
this.ess = ess;
history.add(20d);
}
@Override
public void run() {
final long startTime = System.nanoTime();
final long currentTime = System.currentTimeMillis();
long timeSpent = (startTime - lastPoll) / 1000;
if (timeSpent == 0) {
timeSpent = 1;
}
if (history.size() > 10) {
history.remove();
}
final double tps = tickInterval * 1000000.0 / timeSpent;
if (tps <= 21) {
history.add(tps);
}
lastPoll = startTime;
int count = 0;
onlineUsers.clear();
for (final Player player : ess.getOnlinePlayers()) {
@@ -99,14 +81,4 @@ public class EssentialsTimer implements Runnable {
user.resetInvulnerabilityAfterTeleport();
}
}
public double getAverageTPS() {
double avg = 0;
for (final Double f : history) {
if (f != null) {
avg += f;
}
}
return avg / history.size();
}
}
@@ -28,7 +28,6 @@ import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.regex.Pattern;
@@ -36,7 +35,7 @@ import java.util.regex.Pattern;
public class I18n implements net.ess3.api.II18n {
private static final String MESSAGES = "messages";
private static final Pattern NODOUBLEMARK = Pattern.compile("''");
private static volatile ExecutorService BUNDLE_LOADER_EXECUTOR = Executors.newFixedThreadPool(2);
private static final ExecutorService BUNDLE_LOADER_EXECUTOR = Executors.newFixedThreadPool(2);
private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() {
@SuppressWarnings("NullableProblems")
public Enumeration<String> getKeys() {
@@ -107,29 +106,6 @@ public class I18n implements net.ess3.api.II18n {
public void onDisable() {
instance = null;
shutdownExecutor();
}
private static synchronized ExecutorService getExecutor() {
if (BUNDLE_LOADER_EXECUTOR == null || BUNDLE_LOADER_EXECUTOR.isShutdown() || BUNDLE_LOADER_EXECUTOR.isTerminated()) {
BUNDLE_LOADER_EXECUTOR = Executors.newFixedThreadPool(2);
}
return BUNDLE_LOADER_EXECUTOR;
}
private static synchronized void shutdownExecutor() {
final ExecutorService exec = BUNDLE_LOADER_EXECUTOR;
if (exec == null) {
return;
}
exec.shutdown();
try {
if (!exec.awaitTermination(5, TimeUnit.SECONDS)) {
exec.shutdownNow();
}
} catch (final InterruptedException ignored) {
exec.shutdownNow();
}
}
@Override
@@ -148,7 +124,7 @@ public class I18n implements net.ess3.api.II18n {
synchronized (loadingBundles) {
if (!loadingBundles.contains(locale)) {
loadingBundles.add(locale);
getExecutor().submit(() -> {
BUNDLE_LOADER_EXECUTOR.submit(() -> {
blockingLoadBundle(locale);
synchronized (loadingBundles) {
loadingBundles.remove(locale);
@@ -9,18 +9,19 @@ import com.earth2me.essentials.commands.PlayerNotFoundException;
import com.earth2me.essentials.perm.PermissionsHandler;
import com.earth2me.essentials.updatecheck.UpdateChecker;
import com.earth2me.essentials.userstorage.IUserMap;
import net.ess3.provider.SchedulingProvider;
import net.ess3.provider.Provider;
import net.essentialsx.api.v2.services.BalanceTop;
import net.essentialsx.api.v2.services.mail.MailService;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import java.util.Collection;
import java.util.List;
@@ -80,10 +81,6 @@ public interface IEssentials extends Plugin {
ISettings getSettings();
BukkitScheduler getScheduler();
List<Player> getJailedPlayers();
IJails getJails();
IWarps getWarps();
@@ -98,17 +95,45 @@ public interface IEssentials extends Plugin {
UpdateChecker getUpdateChecker();
BukkitTask runTaskAsynchronously(Runnable run);
void runTaskAsynchronously(Runnable run);
BukkitTask runTaskLaterAsynchronously(Runnable run, long delay);
void runTaskLaterAsynchronously(Runnable run, long delay);
BukkitTask runTaskTimerAsynchronously(Runnable run, long delay, long period);
SchedulingProvider.EssentialsTask runTaskTimerAsynchronously(Runnable run, long delay, long period);
int scheduleSyncDelayedTask(Runnable run);
void scheduleEntityDelayedTask(Entity entity, Runnable run);
int scheduleSyncDelayedTask(Runnable run, long delay);
SchedulingProvider.EssentialsTask scheduleEntityDelayedTask(Entity entity, Runnable run, long delay);
int scheduleSyncRepeatingTask(Runnable run, long delay, long period);
SchedulingProvider.EssentialsTask scheduleEntityRepeatingTask(Entity entity, Runnable run, long delay, long period);
void scheduleLocationDelayedTask(Location location, Runnable run);
void scheduleLocationDelayedTask(Location location, Runnable run, long delay);
SchedulingProvider.EssentialsTask scheduleLocationRepeatingTask(Location location, Runnable run, long delay, long period);
default void scheduleGlobalDelayedTask(Runnable run) {
scheduleGlobalDelayedTask(run, 1);
}
void scheduleGlobalDelayedTask(Runnable run, long delay);
SchedulingProvider.EssentialsTask scheduleGlobalRepeatingTask(Runnable run, long delay, long period);
void scheduleInitTask(Runnable runnable);
boolean isEntityThread(Entity entity);
boolean isRegionThread(Location location);
boolean isGlobalThread();
void ensureEntity(Entity entity, Runnable runnable);
void ensureRegion(Location location, Runnable runnable);
void ensureGlobal(Runnable runnable);
PermissionsHandler getPermissionsHandler();
@@ -94,8 +94,6 @@ public interface ISettings extends IConf {
String getNicknamePrefix();
boolean isResetNickOnNameChange();
String getOperatorColor() throws Exception;
boolean getPerWarpPermission();
@@ -136,8 +134,6 @@ public interface ISettings extends IConf {
boolean isAlwaysTeleportSafety();
boolean isConsiderWorldHeightForTeleportSafety();
boolean isTeleportPassengerDismount();
boolean isForcePassengerTeleport();
@@ -225,8 +221,6 @@ public interface ISettings extends IConf {
boolean cancelAfkOnChat();
boolean cancelAfkOnFish();
boolean sleepIgnoresAfkPlayers();
boolean sleepIgnoresVanishedPlayers();
@@ -32,8 +32,6 @@ import java.util.regex.Pattern;
public interface IUser {
boolean isAuthorized(String node);
boolean isAuthorizedCached(String node);
boolean isAuthorized(IEssentialsCommand cmd);
boolean isAuthorized(IEssentialsCommand cmd, String permissionPrefix);
@@ -13,7 +13,6 @@ import net.ess3.api.IEssentials;
import net.ess3.api.TranslatableException;
import net.ess3.provider.BannerDataProvider;
import net.ess3.provider.ItemUnbreakableProvider;
import net.ess3.provider.PatternTypeProvider;
import net.ess3.provider.PotionMetaProvider;
import org.bukkit.Color;
import org.bukkit.DyeColor;
@@ -208,13 +207,8 @@ public class MetaItemStack {
try {
final String components = Joiner.on(' ').join(Arrays.asList(string).subList(fromArg, string.length));
// From 1.20.6 through 1.21.11, modifyItemStack parses its argument as a full item string, so the item's
// namespaced key must be prepended to the components. As of 26.1, the implementation prepends the item
// key itself, so prepending it here would produce a malformed (double-namespaced) item string.
final String itemString = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v26_1_R01)
? components
: stack.getType().getKey() + components;
stack = ess.getServer().getUnsafe().modifyItemStack(stack, itemString);
// modifyItemStack requires that the item namespaced key is prepended to the components for some reason
stack = ess.getServer().getUnsafe().modifyItemStack(stack, stack.getType().getKey() + components);
} catch (final NullPointerException npe) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Itemstack is invalid", npe);
@@ -314,14 +308,8 @@ public class MetaItemStack {
final BookMeta meta = (BookMeta) stack.getItemMeta();
meta.setTitle(title);
stack.setItemMeta(meta);
} else if (split.length > 1 && split[0].startsWith("page") && split[0].length() > 4
&& MaterialUtil.isEditableBook(stack.getType())
&& hasMetaPermission(sender, "page", false, true, ess)) {
final int page = NumberUtil.isInt(split[0].substring(4)) ? (Integer.parseInt(split[0].substring(4)) - 1)
: 0;
if (page > 100) {
throw new TranslatableException("pageLimitExceeded");
}
} else if (split.length > 1 && split[0].startsWith("page") && split[0].length() > 4 && MaterialUtil.isEditableBook(stack.getType()) && hasMetaPermission(sender, "page", false, true, ess)) {
final int page = NumberUtil.isInt(split[0].substring(4)) ? (Integer.parseInt(split[0].substring(4)) - 1) : 0;
final BookMeta meta = (BookMeta) stack.getItemMeta();
final List<String> pages = meta.hasPages() ? new ArrayList<>(meta.getPages()) : new ArrayList<>();
final List<String> lines = new ArrayList<>();
@@ -718,15 +706,22 @@ public class MetaItemStack {
throw new TranslatableException("invalidBanner", split[1]);
}
final PatternType patternType = ess.provider(PatternTypeProvider.class).getPatternTypeByIdentifier(split[0]);
PatternType patternType = null;
try {
//noinspection removal
patternType = PatternType.getByIdentifier(split[0]);
} catch (final Exception ignored) {
}
final BannerMeta meta = (BannerMeta) stack.getItemMeta();
if (split[0].equalsIgnoreCase("basecolor")) {
final Color color = Color.fromRGB(Integer.parseInt(split[1]));
ess.provider(BannerDataProvider.class).setBaseColor(stack, DyeColor.getByColor(color));
} else if (patternType != null) {
//noinspection removal
final PatternType type = PatternType.getByIdentifier(split[0]);
final DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.parseInt(split[1])));
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, patternType);
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, type);
meta.addPattern(pattern);
}
@@ -738,7 +733,12 @@ public class MetaItemStack {
throw new TranslatableException("invalidBanner", split[1]);
}
final PatternType patternType = ess.provider(PatternTypeProvider.class).getPatternTypeByIdentifier(split[0]);
PatternType patternType = null;
try {
//noinspection removal
patternType = PatternType.getByIdentifier(split[0]);
} catch (final Exception ignored) {
}
// Hacky fix for accessing Shield meta - https://github.com/drtshock/Essentials/pull/745#issuecomment-234843795
final BlockStateMeta meta = (BlockStateMeta) stack.getItemMeta();
@@ -747,8 +747,10 @@ public class MetaItemStack {
final Color color = Color.fromRGB(Integer.parseInt(split[1]));
banner.setBaseColor(DyeColor.getByColor(color));
} else if (patternType != null) {
//noinspection removal
final PatternType type = PatternType.getByIdentifier(split[0]);
final DyeColor color = DyeColor.getByColor(Color.fromRGB(Integer.parseInt(split[1])));
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, patternType);
final org.bukkit.block.banner.Pattern pattern = new org.bukkit.block.banner.Pattern(color, type);
banner.addPattern(pattern);
}
banner.update();
@@ -60,7 +60,6 @@ public enum Mob {
CHERRY_BOAT("CherryBoat", Enemies.NEUTRAL, "CHERRY_BOAT"),
BAMBOO_RAFT("BambooRaft", Enemies.NEUTRAL, "BAMBOO_RAFT"),
PALE_OAK_BOAT("PaleOakBoat", Enemies.NEUTRAL, "PALE_OAK_BOAT"),
POPLAR_BOAT("PoplarBoat", Enemies.NEUTRAL, "POPLAR_BOAT"),
MINECART("Minecart", Enemies.NEUTRAL, EntityType.MINECART),
MINECART_CHEST("ChestMinecart", Enemies.NEUTRAL, MobCompat.CHEST_MINECART),
MINECART_FURNACE("FurnaceMinecart", Enemies.NEUTRAL, MobCompat.FURNACE_MINECART),
@@ -119,17 +118,7 @@ public enum Mob {
FROG("Frog", Enemies.FRIENDLY, "FROG"),
TADPOLE("Tadpole", Enemies.FRIENDLY, "TADPOLE"),
WARDEN("Warden", Enemies.ENEMY, "WARDEN"),
CHEST_BOAT("ChestBoat", Enemies.NEUTRAL, MobCompat.OAK_CHEST_BOAT),
ACACIA_CHEST_BOAT("AcaciaChestBoat", Enemies.NEUTRAL, "ACACIA_CHEST_BOAT"),
DARK_OAK_CHEST_BOAT("DarkOakChestBoat", Enemies.NEUTRAL, "DARK_OAK_CHEST_BOAT"),
BIRCH_CHEST_BOAT("BirchChestBoat", Enemies.NEUTRAL, "BIRCH_CHEST_BOAT"),
JUNGLE_CHEST_BOAT("JungleChestBoat", Enemies.NEUTRAL, "JUNGLE_CHEST_BOAT"),
SPRUCE_CHEST_BOAT("SpruceChestBoat", Enemies.NEUTRAL, "SPRUCE_CHEST_BOAT"),
MANGROVE_CHEST_BOAT("MangroveChestBoat", Enemies.NEUTRAL, "MANGROVE_CHEST_BOAT"),
CHERRY_CHEST_BOAT("CherryChestBoat", Enemies.NEUTRAL, "CHERRY_CHEST_BOAT"),
BAMBOO_CHEST_RAFT("BambooChestRaft", Enemies.NEUTRAL, "BAMBOO_CHEST_RAFT"),
PALE_OAK_CHEST_BOAT("PaleOakChestBoat", Enemies.NEUTRAL, "PALE_OAK_CHEST_BOAT"),
POPLAR_CHEST_BOAT("PoplarChestBoat", Enemies.NEUTRAL, "POPLAR_CHEST_BOAT"),
CHEST_BOAT("ChestBoat", Enemies.NEUTRAL, "CHEST_BOAT"),
CAMEL("Camel", Enemies.FRIENDLY, "CAMEL"),
SNIFFER("Sniffer", Enemies.FRIENDLY, "SNIFFER"),
ARMADILLO("Armadillo", Enemies.FRIENDLY, "ARMADILLO"),
@@ -142,8 +131,6 @@ public enum Mob {
NAUTILUS("Nautilus", Enemies.NEUTRAL, "NAUTILUS"),
ZOMBIE_NAUTILUS("ZombieNautilus", Enemies.NEUTRAL, "ZOMBIE_NAUTILUS"),
PARCHED("Parched", Enemies.ENEMY, "PARCHED"),
SULFUR_CUBE("SulfurCube", Enemies.FRIENDLY, "SULFUR_CUBE"),
CUSHION("Cushion", Enemies.FRIENDLY, "CUSHION")
;
private static final Map<String, Mob> hashMap = new HashMap<>();
@@ -88,7 +88,6 @@ public final class MobCompat {
public static final EntityType END_CRYSTAL = getEntityType("END_CRYSTAL", "ENDER_CRYSTAL");
public static final EntityType FIREWORK_ROCKET = getEntityType("FIREWORK_ROCKET", "FIREWORK");
public static final EntityType OAK_BOAT = getEntityType("BOAT", "OAK_BOAT");
public static final EntityType OAK_CHEST_BOAT = getEntityType("CHEST_BOAT", "OAK_CHEST_BOAT");
private MobCompat() {
}
@@ -410,7 +409,6 @@ public final class MobCompat {
OAK("GENERIC", "OAK"),
SPRUCE("REDWOOD", "SPRUCE"),
MANGROVE("GENERIC", "MANGROVE"),
POPLAR("GENERIC", "POPLAR"),
;
private final String treeSpecies;
@@ -55,8 +55,8 @@ public enum MobData {
BABY_VILLAGER("child", EntityType.VILLAGER, Data.BABY, false),
TAMED_TAMEABLE("tamed", Tameable.class, Data.TAMED, true),
TAME_TAMEABLE("tame", Tameable.class, Data.TAMED, false),
RANDOM_COLORABLE("random", Colorable.class, Data.COLORABLE, true),
COLORABLE("", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()), Colorable.class, Data.COLORABLE, true),
RANDOM_SHEEP("random", EntityType.SHEEP, Data.COLORABLE, true),
COLORABLE_SHEEP("", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()), EntityType.SHEEP, Data.COLORABLE, true),
POLKA_HORSE("polka", EntityType.HORSE, Horse.Style.BLACK_DOTS, true),
SOOTY_HORSE("sooty", EntityType.HORSE, Horse.Style.BLACK_DOTS, false),
BLAZE_HORSE("blaze", EntityType.HORSE, Horse.Style.WHITE, true),
@@ -181,6 +181,8 @@ public enum MobData {
WHITE_TRADER_LLAMA("white", MobCompat.TRADER_LLAMA, "llama:WHITE", true),
BROWN_TRADER_LLAMA("brown", MobCompat.TRADER_LLAMA, "llama:BROWN", true),
GRAY_TRADER_LLAMA("gray", MobCompat.TRADER_LLAMA, "llama:GRAY", true),
RANDOM_SHULKER("random", MobCompat.SHULKER, Data.COLORABLE, true),
COLORABLE_SHULKER("", Arrays.stream(DyeColor.values()).map(color -> color.name().toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()), MobCompat.SHULKER, Data.COLORABLE, true),
RED_FOX("red", MobCompat.FOX, "fox:RED", true),
SNOW_FOX("snow", MobCompat.FOX, "fox:SNOW", true),
SIZE_PHANTOM("", Collections.singletonList("<1-100>"), MobCompat.PHANTOM, Data.SIZE, true),
@@ -206,13 +208,12 @@ public enum MobData {
JUNGLE_BOAT("jungle", Boat.class, MobCompat.BoatVariant.JUNGLE, true),
REDWOOD_BOAT("redwood", Boat.class, MobCompat.BoatVariant.REDWOOD, true),
MANGROVE_BOAT("mangrove", Boat.class, MobCompat.BoatVariant.MANGROVE, true),
POPLAR_BOAT("poplar", Boat.class, MobCompat.BoatVariant.POPLAR, true),
OAK_BOAT("oak", Boat.class, MobCompat.BoatVariant.OAK, true),
SPRUCE_BOAT("spruce", Boat.class, MobCompat.BoatVariant.SPRUCE, true),
SADDLE_CAMEL("saddle", MobCompat.CAMEL, Data.CAMELSADDLE, true),
PALE_WOLF("pale", EntityType.WOLF, "wolf:PALE", true),
SPOTTED_WOLF("spotted", EntityType.WOLF, "wolf:SPOTTED", true),
SNOWY_WOLF("snowy", EntityType.WOLF, "wolf:SNOWY", true),
SPOTTED_WOLF("spotted", EntityType.WOLF, "wolf:PALE", true),
SNOWY_WOLF("snowy", EntityType.WOLF, "wolf:PALE", true),
BLACK_WOLF("black", EntityType.WOLF, "wolf:BLACK", true),
ASHEN_WOLF("ashen", EntityType.WOLF, "wolf:ASHEN", true),
RUSTY_WOLF("rusty", EntityType.WOLF, "wolf:RUSTY", true),
@@ -156,7 +156,7 @@ public class RandomTeleport implements IConf {
// Prompts caching random valid locations, up to a maximum number of attempts.
public void cacheRandomLocations(final String name) {
ess.getServer().getScheduler().scheduleSyncDelayedTask(ess, () -> {
ess.runTaskAsynchronously(() -> {
for (int i = 0; i < this.getFindAttempts(); ++i) {
calculateRandomLocation(getCenter(name), getMinRange(name), getMaxRange(name)).thenAccept(location -> {
if (isValidRandomLocation(location)) {
@@ -186,7 +186,6 @@ public class RandomTeleport implements IConf {
// Calculates a random location asynchronously.
private CompletableFuture<Location> calculateRandomLocation(final Location center, final double minRange, final double maxRange) {
final CompletableFuture<Location> future = new CompletableFuture<>();
// Find an equally distributed offset by randomly rotating a point inside a rectangle about the origin
final double rectX = RANDOM.nextDouble() * (maxRange - minRange) + minRange;
final double rectZ = RANDOM.nextDouble() * (maxRange + minRange) - minRange;
@@ -214,15 +213,14 @@ public class RandomTeleport implements IConf {
360 * RANDOM.nextFloat() - 180,
0
);
PaperLib.getChunkAtAsync(location).thenAccept(chunk -> {
return PaperLib.getChunkAtAsync(location).thenApply(chunk -> { // FIXME: use thenApplyAsync + an Executor that runs tasks on the correct region thread to be fully safe.
if (World.Environment.NETHER.equals(center.getWorld().getEnvironment())) {
location.setY(getNetherYAt(location));
} else {
location.setY(center.getWorld().getHighestBlockYAt(location) + HIGHEST_BLOCK_Y_OFFSET);
}
future.complete(location);
return location;
});
return future;
}
// Returns an appropriate elevation for a given location in the nether, or MIN_VALUE if none is found
@@ -147,7 +147,6 @@ public class Settings implements net.ess3.api.ISettings {
private boolean logCommandBlockCommands;
private boolean logConsoleCommands;
private Set<Predicate<String>> nickBlacklist;
private boolean resetNickOnNameChange;
private double maxProjectileSpeed;
private boolean removeEffectsOnHeal;
private Map<String, String> worldAliases;
@@ -297,11 +296,6 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("force-safe-teleport-location", false);
}
@Override
public boolean isConsiderWorldHeightForTeleportSafety() {
return config.getBoolean("consider-world-height-for-teleport-safety", false);
}
@Override
public boolean isTeleportPassengerDismount() {
return config.getBoolean("teleport-passenger-dismount", true);
@@ -514,20 +508,11 @@ public class Settings implements net.ess3.api.ISettings {
return config.getString("nickname-prefix", "~");
}
private boolean _resetNickOnNameChange() {
return config.getBoolean("reset-nick-on-name-change", false);
}
@Override
public String getNicknamePrefix() {
return nicknamePrefix;
}
@Override
public boolean isResetNickOnNameChange() {
return resetNickOnNameChange;
}
@Override
public double getTeleportCooldown() {
return config.getDouble("teleport-cooldown", 0);
@@ -852,7 +837,7 @@ public class Settings implements net.ess3.api.ISettings {
if (reloadCount.get() < 2) {
// on startup: add plugins again in case they registered commands with the new API
// we need to schedule this task before any of the below tasks using _addAlternativeCommand.
ess.scheduleSyncDelayedTask(() -> {
ess.scheduleGlobalDelayedTask(() -> {
for (final Plugin plugin : ess.getServer().getPluginManager().getPlugins()) {
if (plugin.isEnabled()) {
ess.getAlternativeCommandsHandler().addPlugin(plugin);
@@ -878,7 +863,7 @@ public class Settings implements net.ess3.api.ISettings {
// This is 2 because Settings are reloaded twice in the startup lifecycle
if (reloadCount.get() < 2) {
ess.scheduleSyncDelayedTask(() -> _addAlternativeCommand(effectiveAlias, toDisable));
ess.scheduleGlobalDelayedTask(() -> _addAlternativeCommand(effectiveAlias, toDisable));
} else {
_addAlternativeCommand(effectiveAlias, toDisable);
}
@@ -893,7 +878,7 @@ public class Settings implements net.ess3.api.ISettings {
ess.getLogger().log(Level.INFO, "Syncing commands");
}
if (reloadCount.get() < 2) {
ess.scheduleSyncDelayedTask(syncCommandsProvider::syncCommands);
ess.scheduleGlobalDelayedTask(syncCommandsProvider::syncCommands);
} else {
syncCommandsProvider.syncCommands();
}
@@ -901,7 +886,6 @@ public class Settings implements net.ess3.api.ISettings {
}
nicknamePrefix = _getNicknamePrefix();
resetNickOnNameChange = _resetNickOnNameChange();
operatorColor = _getOperatorColor();
changePlayerListName = _changePlayerListName();
configDebug = _isDebug();
@@ -1336,11 +1320,6 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("cancel-afk-on-chat", true);
}
@Override
public boolean cancelAfkOnFish() {
return config.getBoolean("cancel-afk-on-fish", true);
}
@Override
public boolean sleepIgnoresAfkPlayers() {
return sleepIgnoresAfkPlayers;
@@ -32,10 +32,6 @@ public final class SpawnMob {
private static final Material GOLDEN_HELMET = EnumUtil.getMaterial("GOLDEN_HELMET", "GOLD_HELMET");
private static final Material GOLDEN_CHESTPLATE = EnumUtil.getMaterial("GOLDEN_CHESTPLATE", "GOLD_CHESTPLATE");
private static final Material COPPER_HELMET = EnumUtil.getMaterial("COPPER_HELMET");
private static final Material COPPER_CHESTPLATE = EnumUtil.getMaterial("COPPER_CHESTPLATE");
private static final Material COPPER_LEGGINGS = EnumUtil.getMaterial("COPPER_LEGGINGS");
private static final Material COPPER_BOOTS = EnumUtil.getMaterial("COPPER_BOOTS");
private static final Material GOLDEN_LEGGINGS = EnumUtil.getMaterial("GOLDEN_LEGGINGS", "GOLD_LEGGINGS");
private static final Material GOLDEN_BOOTS = EnumUtil.getMaterial("GOLDEN_BOOTS", "GOLD_BOOTS");
private static final Material GOLDEN_SWORD = EnumUtil.getMaterial("GOLDEN_SWORD", "GOLD_SWORD");
@@ -214,11 +210,6 @@ public final class SpawnMob {
invent.setLeggings(new ItemStack(Material.NETHERITE_LEGGINGS, 1));
invent.setChestplate(new ItemStack(Material.NETHERITE_CHESTPLATE, 1));
invent.setHelmet(new ItemStack(Material.NETHERITE_HELMET, 1));
} else if (inputData.contains("copper") && COPPER_HELMET != null) {
invent.setBoots(new ItemStack(COPPER_BOOTS, 1));
invent.setLeggings(new ItemStack(COPPER_LEGGINGS, 1));
invent.setChestplate(new ItemStack(COPPER_CHESTPLATE, 1));
invent.setHelmet(new ItemStack(COPPER_HELMET, 1));
} else if (inputData.contains("diamond")) {
invent.setBoots(new ItemStack(Material.DIAMOND_BOOTS, 1));
invent.setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS, 1));
@@ -23,7 +23,6 @@ import net.ess3.api.events.JailStatusChangeEvent;
import net.ess3.api.events.MuteStatusChangeEvent;
import net.ess3.api.events.UserBalanceUpdateEvent;
import net.ess3.provider.PlayerLocaleProvider;
import net.essentialsx.api.v2.events.PreTransactionEvent;
import net.essentialsx.api.v2.events.TransactionEvent;
import net.essentialsx.api.v2.services.mail.MailSender;
import org.bukkit.Location;
@@ -147,19 +146,6 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return result;
}
@Override
public boolean isAuthorizedCached(final String node) {
if (Essentials.TESTING) {
return false;
}
final boolean result = isAuthorizedCachedCheck(node);
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "checking if " + base.getName() + " has " + node + " (cached) - " + result);
}
return result;
}
@Override
public boolean isPermissionSet(final String node) {
if (Essentials.TESTING) {
@@ -199,24 +185,6 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
}
private boolean isAuthorizedCachedCheck(final String node) {
if (base instanceof OfflinePlayerStub) {
return false;
}
try {
return ess.getPermissionsHandler().hasPermissionCached(base, node);
} catch (final Exception ex) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.SEVERE, "Permission System Error: " + ess.getPermissionsHandler().getName() + " returned: " + ex.getMessage(), ex);
} else {
ess.getLogger().log(Level.SEVERE, "Permission System Error: " + ess.getPermissionsHandler().getName() + " returned: " + ex.getMessage());
}
return false;
}
}
private boolean isPermSetCheck(final String node) {
if (base instanceof OfflinePlayerStub) {
return false;
@@ -295,20 +263,12 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
payUser(reciever, value, UserBalanceUpdateEvent.Cause.UNKNOWN);
}
public void payUser(final User reciever, BigDecimal value, final UserBalanceUpdateEvent.Cause cause) throws Exception {
public void payUser(final User reciever, final BigDecimal value, final UserBalanceUpdateEvent.Cause cause) throws Exception {
if (value.compareTo(BigDecimal.ZERO) < 1) {
throw new Exception(tlLocale(playerLocale, "payMustBePositive"));
}
if (canAfford(value)) {
// Call an event for pre-transaction
final PreTransactionEvent preTransactionEvent = new PreTransactionEvent(this.getSource(), reciever, value);
ess.getServer().getPluginManager().callEvent(preTransactionEvent);
if (preTransactionEvent.isCancelled()) {
return;
}
value = preTransactionEvent.getAmount();
setMoney(getMoney().subtract(value), cause);
reciever.setMoney(reciever.getMoney().add(value), cause);
sendTl("moneySentTo", AdventureUtil.parsed(NumberUtil.displayCurrency(value, ess)), reciever.getDisplayName());
@@ -617,8 +577,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
final BigDecimal value = _getMoney();
final long elapsed = System.nanoTime() - start;
if (elapsed > ess.getSettings().getEconomyLagWarning()) {
ess.getLogger().log(Level.INFO, String.format(Locale.ROOT,
"Lag Notice - Slow Economy Response - Request took over %.3fms!", elapsed / 1_000_000.0));
ess.getLogger().log(Level.INFO, "Lag Notice - Slow Economy Response - Request took over {0}ms!", elapsed / 1000000.0);
}
return value;
}
@@ -823,24 +782,6 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
return false;
}
// Notifies this (muted) user that they have been silenced, including the reason and remaining time if applicable.
public void notifyMuted() {
final String dateDiff = getMuteTimeout() > 0 ? DateUtil.formatDateDiff(getMuteTimeout()) : null;
if (dateDiff == null) {
if (hasMuteReason()) {
sendTl("voiceSilencedReason", getMuteReason());
} else {
sendTl("voiceSilenced");
}
} else {
if (hasMuteReason()) {
sendTl("voiceSilencedReasonTime", dateDiff, getMuteReason());
} else {
sendTl("voiceSilencedTime", dateDiff);
}
}
}
@Override
public long getLastActivityTime() {
return this.lastActivity;
@@ -880,7 +821,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
public void updateActivityOnChat(final boolean broadcast) {
if (ess.getSettings().cancelAfkOnChat()) {
//Chat happens async, make sure we have a sync context
ess.scheduleSyncDelayedTask(() -> updateActivity(broadcast, AfkStatusChangeEvent.Cause.CHAT));
ess.scheduleEntityDelayedTask(base, () -> updateActivity(broadcast, AfkStatusChangeEvent.Cause.CHAT));
}
}
@@ -906,7 +847,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
for (final User user : ess.getOnlineUsers()) {
if (user.isAuthorized("essentials.kick.notify")) {
user.sendTl("playerKicked", Console.displayName(), getName(), user.playerTl("autoAfkKickReason", kickTime));
user.sendTl("playerKicked", Console.DISPLAY_NAME, getName(), user.playerTl("autoAfkKickReason", kickTime));
}
}
} else {
@@ -922,7 +863,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
}
}
final long autoafk = ess.getSettings().getAutoAfk();
if (!isAfk() && autoafk > 0 && lastActivity + autoafk * 1000 < System.currentTimeMillis() && isAuthorizedCached("essentials.afk.auto")) {
if (!isAfk() && autoafk > 0 && lastActivity + autoafk * 1000 < System.currentTimeMillis() && isAuthorized("essentials.afk.auto")) {
setAfk(true, AfkStatusChangeEvent.Cause.ACTIVITY);
if (isAfk() && !isHidden()) {
setDisplayNick();
@@ -42,9 +42,7 @@ public abstract class UserData extends PlayerExtension implements IConf {
super(base);
this.ess = (Essentials) ess;
final File folder = new File(ess.getDataFolder(), "userdata");
// mkdirs() may return false if another thread created the folder concurrently,
// so fall back to checking whether the directory now exists to avoid a race.
if (!folder.isDirectory() && !folder.mkdirs() && !folder.isDirectory()) {
if (!folder.exists() && !folder.mkdirs()) {
throw new RuntimeException("Unable to create userdata folder!");
}
@@ -471,15 +469,6 @@ public abstract class UserData extends PlayerExtension implements IConf {
config.save();
}
public boolean isFlyModeEnabled() {
return holder.flyMode();
}
public void setFlyModeEnabled(final boolean set) {
holder.flyMode(set);
config.save();
}
public boolean getMuted() {
return holder.muted();
}
@@ -21,18 +21,17 @@ import java.util.Locale;
public class SpigotAdventureFacet implements AdventureFacet {
private static final LegacyComponentSerializer LEGACY_SERIALIZER;
private static final LegacyComponentSerializer LEGACY_SERIALIZER_URLS;
private static final MiniMessage MINI_MESSAGE_NO_TAGS;
static {
final LegacyComponentSerializer.Builder builder = LegacyComponentSerializer.builder()
.flattener(ComponentFlattener.basic())
.extractUrls(AbstractChatEvent.URL_PATTERN)
.useUnusualXRepeatedCharacterHexFormat();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_16_1_R01)) {
builder.hexColors();
}
LEGACY_SERIALIZER = builder.build();
LEGACY_SERIALIZER_URLS = builder.extractUrls(AbstractChatEvent.URL_PATTERN).build();
MINI_MESSAGE_NO_TAGS = MiniMessage.builder().strict(true).build();
}
@@ -76,7 +75,7 @@ public class SpigotAdventureFacet implements AdventureFacet {
@Override
public String legacyToMini(String message) {
return legacyToMini(message, false);
return legacyToMini(message, true);
}
@Override
@@ -128,11 +127,6 @@ public class SpigotAdventureFacet implements AdventureFacet {
return miniMessageInstance.stripTags(input);
}
@Override
public String legacyToMiniWithUrls(String message) {
return miniMessageInstance.serialize(LEGACY_SERIALIZER_URLS.deserialize(message));
}
@Override
public String escapeTags(String input) {
return miniMessageInstance.escapeTags(input);
@@ -323,13 +323,7 @@ public class Economy {
throw new IllegalArgumentException("Economy user cannot be null");
}
final BigDecimal result = getMoneyExact(user).add(amount, MATH_CONTEXT);
// Deposits (positive amounts) always improve the balance, so minMoney and
// loan checks don't apply — they exist to prevent the balance from dropping.
if (amount.signum() <= 0) {
setMoney(user, result);
} else {
user.setMoney(result, UserBalanceUpdateEvent.Cause.API);
}
setMoney(user, result);
Trade.log("API", "Add", "API", user.getName(), new Trade(amount, ess), null, null, null, result, ess);
}
@@ -44,7 +44,7 @@ public class Commandbalancetop extends EssentialsCommand {
new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender);
};
if (sender.getSender() instanceof BlockCommandSender) {
ess.scheduleSyncDelayedTask(runnable);
ess.scheduleGlobalDelayedTask(runnable);
} else {
runnable.run();
}
@@ -42,7 +42,7 @@ public class Commandban extends EssentialsCommand {
}
final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME;
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.displayName();
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
final String banReason;
if (args.length > 1) {
banReason = FormatUtil.replaceFormat(getFinalArg(args, 1).replace("\\n", "\n").replace("|", "\n"));
@@ -26,7 +26,7 @@ public class Commandbanip extends EssentialsCommand {
}
final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME;
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.displayName();
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
String ipAddress;
if (FormatUtil.validIP(args[0])) {
@@ -23,7 +23,7 @@ public class Commandbeezooka extends EssentialsCommand {
final Entity bee = Mob.BEE.spawn(user.getWorld(), server, user.getBase().getEyeLocation());
bee.setVelocity(user.getBase().getEyeLocation().getDirection().multiply(2));
ess.scheduleSyncDelayedTask(() -> {
ess.scheduleEntityDelayedTask(bee, () -> {
final Location loc = bee.getLocation();
bee.remove();
loc.getWorld().createExplosion(loc, 0F);
@@ -1,7 +1,6 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.adventure.AdventureUtil;
import com.earth2me.essentials.utils.FormatUtil;
import org.bukkit.Server;
@@ -16,9 +15,6 @@ public class Commandbroadcast extends EssentialsCommand {
throw new NotEnoughArgumentsException();
}
final String message = FormatUtil.replaceFormat(getFinalArg(args, 0)).replace("\\n", "\n");
ess.broadcastTl("broadcast",
AdventureUtil.parsed(ess.getAdventureFacet().legacyToMiniWithUrls(ess.getAdventureFacet().escapeTags(message))),
sender.getDisplayName());
ess.broadcastTl("broadcast", FormatUtil.replaceFormat(getFinalArg(args, 0)).replace("\\n", "\n"), sender.getDisplayName());
}
}
@@ -54,11 +54,7 @@ public class Commandbroadcastworld extends EssentialsCommand {
if (message.isEmpty()) {
throw new NotEnoughArgumentsException();
}
final String formatted = FormatUtil.replaceFormat(message).replace("\\n", "\n");
ess.broadcastTl(null, u -> !u.getBase().getWorld().equals(world), true, "broadcast",
AdventureUtil.parsed(
ess.getAdventureFacet().legacyToMiniWithUrls(ess.getAdventureFacet().escapeTags(formatted))),
AdventureUtil.parsed(ess.getAdventureFacet().legacyToMini(name)));
ess.broadcastTl(null, u -> !u.getBase().getWorld().equals(world), true, "broadcast", FormatUtil.replaceFormat(message).replace("\\n", "\n"), AdventureUtil.parsed(ess.getAdventureFacet().legacyToMini(name)));
}
@Override
@@ -19,12 +19,8 @@ public class Commandburn extends EssentialsCommand {
}
final User user = getPlayer(server, sender, args, 0);
final int seconds = Integer.parseInt(args[1]);
final int fireTicks = (int) Math.max(0L, Math.min((long) seconds * 20, Integer.MAX_VALUE));
user.getBase().setFireTicks(fireTicks);
sender.sendTl("burnMsg", user.getDisplayName(), Math.max(0, seconds));
user.getBase().setFireTicks(Integer.parseInt(args[1]) * 20);
sender.sendTl("burnMsg", user.getDisplayName(), Integer.parseInt(args[1]));
}
@Override
@@ -12,8 +12,7 @@ public class Commanddisposal extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
user.sendTl("openingDisposal");
final String title = ess.getAdventureFacet().miniToLegacy(user.playerTl("disposal"));
user.getBase().openInventory(ess.getServer().createInventory(user.getBase(), 36, title));
user.getBase().openInventory(ess.getServer().createInventory(user.getBase(), 36, user.playerTl("disposal")));
}
}
@@ -9,7 +9,6 @@ import com.google.common.collect.Lists;
import net.ess3.api.MaxMoneyException;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.UserBalanceUpdateEvent;
import net.ess3.provider.PlayerLocaleProvider;
import org.bukkit.Server;
import java.math.BigDecimal;
@@ -35,14 +34,7 @@ public class Commandeco extends EssentialsLoopCommand {
try {
cmd = EcoCommands.valueOf(args[0].toUpperCase(Locale.ENGLISH));
isPercent = cmd != EcoCommands.RESET && args[2].endsWith("%");
if (cmd == EcoCommands.RESET) {
amount = ess.getSettings().getStartingBalance();
} else if (sender.isPlayer() && ess.getSettings().isPerPlayerLocale()) {
final String playerLocale = ess.provider(PlayerLocaleProvider.class).getLocale(sender.getPlayer());
amount = NumberUtil.parseStringToBDecimal(args[2], ess.getUser(sender.getPlayer()).getPlayerLocale(playerLocale));
} else {
amount = NumberUtil.parseStringToBDecimal(args[2]);
}
amount = (cmd == EcoCommands.RESET) ? ess.getSettings().getStartingBalance() : new BigDecimal(args[2].replaceAll("[^0-9\\.]", ""));
} catch (final Exception ex) {
throw new NotEnoughArgumentsException(ex);
}
@@ -8,7 +8,6 @@ import com.earth2me.essentials.commands.essentials.HomesCommand;
import com.earth2me.essentials.commands.essentials.ItemTestCommand;
import com.earth2me.essentials.commands.essentials.MooCommand;
import com.earth2me.essentials.commands.essentials.NyanCommand;
import com.earth2me.essentials.commands.essentials.ReloadCommand;
import com.earth2me.essentials.commands.essentials.UsermapCommand;
import com.earth2me.essentials.commands.essentials.VersionCommand;
@@ -20,7 +19,6 @@ public class Commandessentials extends EssentialsTreeCommand {
registerNode(new DebugCommand());
registerNode(new CommandMapCommand());
registerNode(new DumpCommand());
registerNode(new ReloadCommand());
registerNode(new CleanupCommand());
registerNode(new HomesCommand());
registerNode(new UsermapCommand());
@@ -147,21 +147,15 @@ public class Commandexp extends EssentialsLoopCommand {
}
return options;
} else if (args.length == 2) {
final ExpCommands cmd;
try {
cmd = ExpCommands.valueOf(args[0].toUpperCase(Locale.ENGLISH));
} catch (final IllegalArgumentException e) {
return Collections.emptyList();
}
if (cmd.hasOtherPermission(user)) {
return getPlayers(user);
}
if (cmd.hasPermission(user) && cmd != ExpCommands.SHOW && cmd != ExpCommands.RESET) {
if ((args[0].equalsIgnoreCase("set") && user.isAuthorized("essentials.exp.set")) || (args[0].equalsIgnoreCase("give") && user.isAuthorized("essentials.exp.give")) || (args[0].equalsIgnoreCase("take") && user.isAuthorized("essentials.exp.take"))) {
final String levellessArg = args[1].toLowerCase(Locale.ENGLISH).replaceAll("l", "");
if (NumberUtil.isInt(levellessArg)) {
return Lists.newArrayList(levellessArg + "l");
}
}
if (user.isAuthorized("essentials.exp.others")) {
return getPlayers(user);
}
} else if (args.length == 3 && !(args[0].equalsIgnoreCase("show") || args[0].equalsIgnoreCase("reset"))) {
final String levellessArg = args[2].toLowerCase(Locale.ENGLISH).replaceAll("l", "");
if (NumberUtil.isInt(levellessArg)) {
@@ -34,8 +34,6 @@ public class Commandfly extends EssentialsToggleCommand {
user.getBase().setFallDistance(0f);
user.getBase().setAllowFlight(enabled);
user.setFlyModeEnabled(enabled);
if (!user.getBase().getAllowFlight()) {
user.getBase().setFlying(false);
}
@@ -3,15 +3,13 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.provider.TileEntityProvider;
import net.ess3.provider.WorldTileEntityCountProvider;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Server;
import org.bukkit.World;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.logging.Level;
public class Commandgc extends EssentialsCommand {
public Commandgc() {
@@ -20,7 +18,7 @@ public class Commandgc extends EssentialsCommand {
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
final double tps = ess.getTimer().getAverageTPS();
final double tps = 20d; //TODO
final ChatColor color;
if (tps >= 18.0) {
color = ChatColor.GREEN;
@@ -37,7 +35,7 @@ public class Commandgc extends EssentialsCommand {
sender.sendTl("gcfree", Runtime.getRuntime().freeMemory() / 1024 / 1024);
final List<World> worlds = server.getWorlds();
final TileEntityProvider tileEntityProvider = ess.provider(TileEntityProvider.class);
final WorldTileEntityCountProvider worldTileEntityCountProvider = ess.provider(WorldTileEntityCountProvider.class);
for (final World w : worlds) {
String worldType = "World";
switch (w.getEnvironment()) {
@@ -49,15 +47,7 @@ public class Commandgc extends EssentialsCommand {
break;
}
int tileEntities = 0;
try {
for (final Chunk chunk : w.getLoadedChunks()) {
tileEntities += tileEntityProvider.getTileEntities(chunk).length;
}
} catch (final java.lang.ClassCastException ex) {
ess.getLogger().log(Level.SEVERE, "Corrupted chunk data on world " + w, ex);
}
final int tileEntities = worldTileEntityCountProvider.getTileEntityCount(w);
sender.sendTl("gcWorld", worldType, w.getName(), w.getLoadedChunks().length, w.getEntities().size(), tileEntities);
}
@@ -54,7 +54,7 @@ public class Commandhelp extends EssentialsCommand {
user.sendTl("commandHelpLine3");
if (essCommand != null && !essCommand.getUsageStrings().isEmpty()) {
for (Map.Entry<String, String> usage : essCommand.getUsageStrings().entrySet()) {
user.sendTl("commandHelpLineUsage", AdventureUtil.parsed(usage.getKey().replace("<command>", cmd)), AdventureUtil.parsed(user.playerTl(usage.getValue())));
user.sendTl("commandHelpLineUsage", AdventureUtil.parsed(usage.getKey().replace("<command>", cmd)), AdventureUtil.parsed(usage.getValue()));
}
} else {
user.sendMessage(bukkit.getUsage());
@@ -41,10 +41,7 @@ public class Commandhome extends EssentialsCommand {
}
}
try {
if ("bed".equalsIgnoreCase(homeName)) {
if (!user.isAuthorized("essentials.home.bed")) {
throw new TranslatableException("noAccessCommand");
}
if ("bed".equalsIgnoreCase(homeName) && user.isAuthorized("essentials.home.bed")) {
if (!player.getBase().isOnline() || player.getBase() instanceof OfflinePlayerStub) {
throw new TranslatableException("bedOffline");
}
@@ -76,15 +73,10 @@ public class Commandhome extends EssentialsCommand {
final List<String> homes = finalPlayer.getHomes();
if (homes.isEmpty() && finalPlayer.equals(user)) {
if (ess.getSettings().isSpawnIfNoHome()) {
final boolean useBed = bed != null && user.isAuthorized("essentials.home.bed");
final UserTeleportHomeEvent event = new UserTeleportHomeEvent(user, null, useBed ? bed : finalPlayer.getWorld().getSpawnLocation(), useBed ? UserTeleportHomeEvent.HomeType.BED : UserTeleportHomeEvent.HomeType.SPAWN);
final UserTeleportHomeEvent event = new UserTeleportHomeEvent(user, null, bed != null ? bed : finalPlayer.getWorld().getSpawnLocation(), bed != null ? UserTeleportHomeEvent.HomeType.BED : UserTeleportHomeEvent.HomeType.SPAWN);
server.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
if (useBed) {
user.getAsyncTeleport().respawn(charge, TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), commandLabel));
} else {
user.getAsyncTeleport().teleport(finalPlayer.getWorld().getSpawnLocation(), charge, TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), commandLabel));
}
user.getAsyncTeleport().respawn(charge, TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), commandLabel));
}
} else {
showError(user.getBase(), new TranslatableException("noHomeSetPlayer"), commandLabel);
@@ -1,23 +0,0 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.utils.StringUtil;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import java.util.stream.Collectors;
public class Commandjailedplayers extends EssentialsCommand {
public Commandjailedplayers() {
super("jailedplayers");
}
@Override
protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
if (ess.getJailedPlayers() != null && !ess.getJailedPlayers().isEmpty()) {
sender.sendTl("jailedPlayersList", StringUtil.joinList(", ", ess.getJailedPlayers().stream().map(Player::getName).collect(Collectors.toList())));
} else {
sender.sendTl("jailedPlayersEmpty");
}
}
}
@@ -50,7 +50,7 @@ public class Commandkick extends EssentialsCommand {
kickReason = event.getReason();
target.getBase().kickPlayer(kickReason);
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.displayName();
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
final String tlKey = "playerKicked";
final Object[] objects = {senderDisplayName, target.getName(), kickReason};
@@ -32,13 +32,15 @@ public class Commandkill extends EssentialsLoopCommand {
}
final DamageEventProvider provider = ess.provider(DamageEventProvider.class);
final EntityDamageEvent ede = provider.callDamageEvent(matchPlayer, sender.isPlayer() && sender.getPlayer().getName().equals(matchPlayer.getName()) ? EntityDamageEvent.DamageCause.SUICIDE : EntityDamageEvent.DamageCause.CUSTOM, Float.MAX_VALUE);
if (ede.isCancelled() && sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.kill.force")) {
return;
}
ede.getEntity().setLastDamageCause(ede);
matchPlayer.setHealth(0);
sender.sendTl("kill", matchPlayer.getDisplayName());
ess.scheduleEntityDelayedTask(matchPlayer, () -> {
final EntityDamageEvent ede = provider.callDamageEvent(matchPlayer, sender.isPlayer() && sender.getPlayer().getName().equals(matchPlayer.getName()) ? EntityDamageEvent.DamageCause.SUICIDE : EntityDamageEvent.DamageCause.CUSTOM, Float.MAX_VALUE);
if (ede.isCancelled() && sender.isPlayer() && !ess.getUser(sender.getPlayer()).isAuthorized("essentials.kill.force")) {
return;
}
ede.getEntity().setLastDamageCause(ede);
matchPlayer.setHealth(0);
sender.sendTl("kill", matchPlayer.getDisplayName());
});
}
@Override
@@ -49,7 +49,7 @@ public class Commandkittycannon extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final Entity ocelot = Mob.CAT.getType() == null ? spawnOcelot(server, user) : spawnCat(server, user);
ess.scheduleSyncDelayedTask(() -> {
ess.scheduleEntityDelayedTask(ocelot, () -> {
final Location loc = ocelot.getLocation();
ocelot.remove();
loc.getWorld().createExplosion(loc, 0F);
@@ -33,15 +33,17 @@ public class Commandlightning extends EssentialsLoopCommand {
}
final int finalPower = power;
loopOnlinePlayersConsumer(server, sender, false, true, args[0], player -> {
sender.sendTl("lightningUse", player.getDisplayName());
final LightningStrike strike = player.getBase().getWorld().strikeLightningEffect(player.getBase().getLocation());
ess.scheduleEntityDelayedTask(player.getBase(), () -> {
sender.sendTl("lightningUse", player.getDisplayName());
final LightningStrike strike = player.getBase().getWorld().strikeLightningEffect(player.getBase().getLocation());
if (!player.isGodModeEnabled()) {
player.getBase().damage(finalPower, strike);
}
if (ess.getSettings().warnOnSmite()) {
player.sendTl("lightningSmited");
}
if (!player.isGodModeEnabled()) {
player.getBase().damage(finalPower, strike);
}
if (ess.getSettings().warnOnSmite()) {
player.sendTl("lightningSmited");
}
});
});
loopOnlinePlayers(server, sender, true, true, args[0], null);
}
@@ -36,13 +36,11 @@ public class Commandmore extends EssentialsCommand {
if (!NumberUtil.isPositiveInt(args[0])) {
throw new TranslatableException("nonZeroPosNumber");
}
final int cap = canOversized ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize();
final long newSizeLong = (long) stack.getAmount() + Integer.parseInt(args[0]);
if (newSizeLong > cap) {
user.sendTl(canOversized ? "fullStackDefaultOversize" : "fullStackDefault", cap);
newStackSize = cap;
} else {
newStackSize = (int) newSizeLong;
newStackSize += Integer.parseInt(args[0]);
if (newStackSize > (canOversized ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize())) {
user.sendTl(canOversized ? "fullStackDefaultOversize" : "fullStackDefault", canOversized ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize());
newStackSize = canOversized ? ess.getSettings().getOversizedStackSize() : stack.getMaxStackSize();
}
} else if (canOversized) {
newStackSize = ess.getSettings().getOversizedStackSize();
@@ -4,7 +4,9 @@ import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.User;
import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
import java.util.Collections;
@@ -25,15 +27,20 @@ public class Commandmsg extends EssentialsLoopCommand {
final boolean canWildcard = sender.isAuthorized("essentials.msg.multiple");
if (sender.isPlayer()) {
final User user = ess.getUser(sender.getPlayer());
// Muted players are handled in SimpleMessageRecipient#sendMessage so that the message can still
// be shown to social spies before being dropped instead of being delivered to the recipient.
if (user.isMuted()) {
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new TranslatableException(user.hasMuteReason() ? "voiceSilencedReason" : "voiceSilenced", user.getMuteReason());
}
throw new TranslatableException(user.hasMuteReason() ? "voiceSilencedReasonTime" : "voiceSilencedTime", dateDiff, user.getMuteReason());
}
message = FormatUtil.formatMessage(user, "essentials.msg", message);
} else {
message = FormatUtil.replaceFormat(message);
}
// Sending messages to console
if (args[0].equalsIgnoreCase(Console.NAME) || args[0].equalsIgnoreCase(Console.displayName())) {
if (args[0].equalsIgnoreCase(Console.NAME) || args[0].equalsIgnoreCase(Console.DISPLAY_NAME)) {
final IMessageRecipient messageSender = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : Console.getInstance();
messageSender.sendMessage(Console.getInstance(), message);
return;
@@ -21,7 +21,6 @@ public class Commandmute extends EssentialsCommand {
@Override
public void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception {
final boolean isUnmute = commandLabel.toLowerCase(java.util.Locale.ENGLISH).contains("unmute");
boolean nomatch = false;
if (args.length < 1) {
throw new NotEnoughArgumentsException();
@@ -33,17 +32,11 @@ public class Commandmute extends EssentialsCommand {
nomatch = true;
user = ess.getUser(new OfflinePlayerStub(args[0], ess.getServer()));
}
if (isUnmute && !user.getMuted()) {
sender.sendTl("playerNotMuted", user.getDisplayName());
return;
}
if (!user.getBase().isOnline() && sender.isPlayer()) {
if (!sender.isAuthorized("essentials.mute.offline")) {
throw new TranslatableException("muteExemptOffline");
}
} else if (!isUnmute && user.isAuthorized("essentials.mute.exempt")) {
} else if (user.isAuthorized("essentials.mute.exempt")) {
throw new TranslatableException("muteExempt");
}
@@ -51,7 +44,7 @@ public class Commandmute extends EssentialsCommand {
final String time;
String muteReason = null;
if (!isUnmute && args.length > 1) {
if (args.length > 1) {
time = args[1];
try {
muteTimestamp = DateUtil.parseDateDiff(time, true);
@@ -66,7 +59,7 @@ public class Commandmute extends EssentialsCommand {
}
}
final boolean willMute = !isUnmute && ((args.length > 1) || !user.getMuted());
final boolean willMute = (args.length > 1) || !user.getMuted();
final User controller = sender.isPlayer() ? ess.getUser(sender.getPlayer()) : null;
final MuteStatusChangeEvent event = new MuteStatusChangeEvent(user, controller, willMute, muteTimestamp, muteReason);
ess.getServer().getPluginManager().callEvent(event);
@@ -128,8 +121,6 @@ public class Commandmute extends EssentialsCommand {
} else {
sender.sendTl("unmutedPlayer", user.getDisplayName());
user.sendTl("playerUnmuted");
ess.getLogger().log(Level.INFO, ess.getAdventureFacet().miniToLegacy(tlLiteral("unmuteNotify", sender.getSender().getName(), user.getName())));
ess.broadcastTl(null, "essentials.mute.notify", "unmuteNotify", new Object[]{sender.getSender().getName(), user.getName()});
}
}
}
@@ -35,17 +35,20 @@ public class Commandnuke extends EssentialsCommand {
if (user == null) {
continue;
}
user.sendTl("nuke");
final Location loc = user.getLocation();
final World world = loc.getWorld();
if (world != null) {
for (int x = -10; x <= 10; x += 5) {
for (int z = -10; z <= 10; z += 5) {
final TNTPrimed entity = world.spawn(new Location(world, loc.getBlockX() + x, world.getHighestBlockYAt(loc) + 64, loc.getBlockZ() + z), TNTPrimed.class);
entity.setMetadata(NUKE_META_KEY, new FixedMetadataValue(ess, true));
ess.scheduleEntityDelayedTask(user.getBase(), () -> {
user.sendTl("nuke");
final Location loc = user.getLocation();
final World world = loc.getWorld();
if (world != null) {
for (int x = -10; x <= 10; x += 5) {
for (int z = -10; z <= 10; z += 5) {
final TNTPrimed entity = world.spawn(new Location(world, loc.getBlockX() + x, world.getHighestBlockYAt(loc) + 64, loc.getBlockZ() + z), TNTPrimed.class);
entity.setMetadata(NUKE_META_KEY, new FixedMetadataValue(ess, true));
}
}
}
}
});
}
}
@@ -4,6 +4,7 @@ import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.Console;
import com.earth2me.essentials.User;
import com.earth2me.essentials.messaging.IMessageRecipient;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.FormatUtil;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
@@ -23,8 +24,14 @@ public class Commandr extends EssentialsCommand {
final IMessageRecipient messageSender;
if (sender.isPlayer()) {
final User user = ess.getUser(sender.getPlayer());
// Muted players are handled in SimpleMessageRecipient#sendMessage so that the message can still
// be shown to social spies before being dropped instead of being delivered to the recipient.
if (user.isMuted()) {
final String dateDiff = user.getMuteTimeout() > 0 ? DateUtil.formatDateDiff(user.getMuteTimeout()) : null;
if (dateDiff == null) {
throw new TranslatableException(user.hasMuteReason() ? "voiceSilencedReason" : "voiceSilenced", user.getMuteReason());
}
throw new TranslatableException(user.hasMuteReason() ? "voiceSilencedReasonTime" : "voiceSilencedTime", dateDiff, user.getMuteReason());
}
message = FormatUtil.formatMessage(user, "essentials.msg", message);
messageSender = user;
} else {
@@ -13,10 +13,8 @@ import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Server;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.FurnaceRecipe;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.RecipeChoice;
@@ -160,13 +158,7 @@ public class Commandrecipe extends EssentialsCommand {
final User user = ess.getUser(sender.getPlayer());
user.getBase().closeInventory();
user.setRecipeSee(true);
final InventoryView view = openWorkbench(user);
if (view == null) {
user.setRecipeSee(false);
return;
}
final Inventory topInventory = ess.provider(InventoryViewProvider.class).getTopInventory(view);
final InventoryView view = user.getBase().openWorkbench(null, true);
final String[] recipeShape = recipe.getShape();
final Map<Character, ItemStack> ingredientMap = recipe.getIngredientMap();
for (int j = 0; j < recipeShape.length; j++) {
@@ -178,7 +170,7 @@ public class Commandrecipe extends EssentialsCommand {
if (VersionUtil.PRE_FLATTENING && item.getDurability() == Short.MAX_VALUE) {
item.setDurability((short) 0);
}
topInventory.setItem(j * 3 + k + 1, item);
ess.provider(InventoryViewProvider.class).getTopInventory(view).setItem(j * 3 + k + 1, item);
}
}
} else {
@@ -225,11 +217,7 @@ public class Commandrecipe extends EssentialsCommand {
final User user = ess.getUser(sender.getPlayer());
user.getBase().closeInventory();
user.setRecipeSee(true);
final InventoryView view = openWorkbench(user);
if (view == null) {
user.setRecipeSee(false);
return;
}
final InventoryView view = user.getBase().openWorkbench(null, true);
for (int i = 0; i < ingredients.size(); i++) {
final ItemStack item = ingredients.get(i);
if (VersionUtil.PRE_FLATTENING && item.getDurability() == Short.MAX_VALUE) {
@@ -251,17 +239,6 @@ public class Commandrecipe extends EssentialsCommand {
}
}
private InventoryView openWorkbench(final User user) {
final InventoryView view = user.getBase().openWorkbench(null, true);
// If InventoryOpenEvent is canceled, the items can end up in the player's own crafting grid
// which allows players to extract counterfeit items.
if (view == null)
return null;
final Inventory inventory = ess.provider(InventoryViewProvider.class).getTopInventory(view);
return inventory.getType() == InventoryType.WORKBENCH ? view : null;
}
public String getMaterialName(final CommandSource sender, final ItemStack stack) {
if (stack == null) {
return sender.tl("recipeNothing");
@@ -61,7 +61,7 @@ public class Commandseen extends EssentialsCommand {
return;
}
}
ess.getScheduler().runTaskAsynchronously(ess, new Runnable() {
ess.runTaskAsynchronously(new Runnable() {
@Override
public void run() {
final User userFromBukkit = ess.getUsers().getUser(args[0]);
@@ -25,10 +25,6 @@ public class Commandsetwarp extends EssentialsCommand {
throw new TranslatableException("invalidWarpName");
}
if (StringUtil.isReservedFileName(args[0])) {
throw new TranslatableException("invalidWarpName");
}
final IWarps warps = ess.getWarps();
Location warpLoc = null;
@@ -159,7 +159,7 @@ public class Commandskull extends EssentialsCommand {
final String shortNameFinal = shortOwnerName;
ess.scheduleSyncDelayedTask(() -> {
ess.scheduleEntityDelayedTask(user.getBase(), () -> {
stack.setItemMeta(skullMeta);
if (spawn) {
Inventories.addItem(receive.getBase(), stack);
@@ -37,8 +37,7 @@ public class Commandspeed extends EssentialsCommand {
final float speed;
final boolean isBypass = user.isAuthorized("essentials.speed.bypass");
if (args.length == 1) {
final boolean inferredFly = isFlyAlias(commandLabel) ? true : isWalkAlias(commandLabel) ? false : user.getBase().isFlying();
isFly = flyPermCheck(user, inferredFly);
isFly = flyPermCheck(user, user.getBase().isFlying());
speed = getMoveSpeed(args[0]);
} else {
isFly = flyPermCheck(user, isFlyMode(args[0]));
@@ -92,14 +91,6 @@ public class Commandspeed extends EssentialsCommand {
} else return !canWalk;
}
private boolean isFlyAlias(final String label) {
return label.contains("fly") || label.equalsIgnoreCase("fspeed") || label.equalsIgnoreCase("efspeed");
}
private boolean isWalkAlias(final String label) {
return label.contains("walk") || label.equalsIgnoreCase("wspeed") || label.equalsIgnoreCase("ewspeed");
}
private boolean isFlyMode(final String modeString) throws NotEnoughArgumentsException {
final boolean isFlyMode;
if (modeString.contains("fly") || modeString.equalsIgnoreCase("f")) {
@@ -53,7 +53,7 @@ public class Commandsudo extends EssentialsLoopCommand {
}
}
ess.scheduleSyncDelayedTask(new SudoCommandTask());
ess.scheduleEntityDelayedTask(user.getBase(), new SudoCommandTask());
}
}
}
@@ -49,7 +49,7 @@ public class Commandtempban extends EssentialsCommand {
}
final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME;
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.displayName();
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
ess.getServer().getBanList(BanList.Type.NAME).addBan(user.getName(), banReason, new Date(banTimestamp), senderName);
final String expiry = DateUtil.formatDateDiff(banTimestamp);
@@ -28,7 +28,7 @@ public class Commandtempbanip extends EssentialsCommand {
}
final String senderName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.NAME;
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.displayName();
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
String ipAddress;
if (FormatUtil.validIP(args[0])) {
@@ -1,7 +1,6 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.CommonPlaceholders;
import com.google.common.collect.Lists;
import org.bukkit.Server;
import org.bukkit.World;
@@ -22,16 +21,17 @@ public class Commandthunder extends EssentialsCommand {
final World world = user.getWorld();
final boolean setThunder = args[0].equalsIgnoreCase("true");
if (args.length == 1) {
world.setThundering(setThunder);
user.sendTl("thunder", CommonPlaceholders.enableDisable(user.getSource(), setThunder));
ess.scheduleGlobalDelayedTask(() -> world.setThundering(setThunder));
user.sendTl("thunder", setThunder ? user.playerTl("enabled") : user.playerTl("disabled"));
return;
}
world.setThundering(setThunder);
world.setThunderDuration(Integer.parseInt(args[1]) * 20);
user.sendTl("thunderDuration", CommonPlaceholders.enableDisable(user.getSource(), setThunder), Integer.parseInt(args[1]));
ess.scheduleGlobalDelayedTask(() -> {
world.setThundering(setThunder);
world.setThunderDuration(Integer.parseInt(args[1]) * 20);
});
user.sendTl("thunderDuration", setThunder ? user.playerTl("enabled") : user.playerTl("disabled"), Integer.parseInt(args[1]));
}
@Override
@@ -8,17 +8,14 @@ import com.google.common.collect.Lists;
import net.ess3.api.TranslatableException;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.TreeSet;
@@ -84,28 +81,16 @@ public class Commandtime extends EssentialsCommand {
}
final StringJoiner joiner = new StringJoiner(", ");
final boolean timeAdd = add;
for (final World world : worlds) {
// Capture intended visible time for players with relative ptime before world time changes
final Map<Player, Long> ptimePlayers = new HashMap<>();
for (final Player player : world.getPlayers()) {
if (player.getPlayerTimeOffset() != 0 && player.isPlayerTimeRelative()) {
ptimePlayers.put(player, player.getPlayerTime());
}
}
long time = world.getTime();
if (!add) {
time -= time % 24000;
}
world.setTime(time + (add ? 0 : 24000) + timeTick);
// Re-apply ptime offsets so players maintain their intended visible time
final long newWorldTime = world.getTime();
for (final Map.Entry<Player, Long> entry : ptimePlayers.entrySet()) {
entry.getKey().setPlayerTime(entry.getValue() - newWorldTime, true);
}
joiner.add(world.getName());
ess.scheduleGlobalDelayedTask(() -> {
long time = world.getTime();
if (!timeAdd) {
time -= time % 24000;
}
world.setTime(time + (timeAdd ? 0 : 24000) + timeTick);
});
}
sender.sendTl(add ? "timeWorldAdd" : "timeWorldSet", DescParseTickFormat.formatTicks(timeTick), joiner.toString());
@@ -56,7 +56,7 @@ public class Commandtp extends EssentialsCommand {
throw new NotEnoughArgumentsException(user.playerTl("teleportInvalidLocation"));
}
final Location locpos = new Location(user.getWorld(), x2, y2, z2, user.getLocation().getYaw(), user.getLocation().getPitch());
user.getAsyncTeleport().now(locpos, true, TeleportCause.COMMAND, future);
user.getAsyncTeleport().now(locpos, false, TeleportCause.COMMAND, future);
future.thenAccept(success -> {
if (success) {
user.sendTl("teleporting", locpos.getWorld().getName(), locpos.getBlockX(), locpos.getBlockY(), locpos.getBlockZ());
@@ -120,7 +120,7 @@ public class Commandtp extends EssentialsCommand {
final User target = getPlayer(server, args, 0, true, false);
if (args.length == 2) {
final User toPlayer = getPlayer(server, args, 1, true, false);
target.sendTl("teleportAtoB", Console.displayName(), toPlayer.getDisplayName());
target.sendTl("teleportAtoB", Console.DISPLAY_NAME, toPlayer.getDisplayName());
target.getAsyncTeleport().now(toPlayer.getBase(), false, TeleportCause.COMMAND, getNewExceptionFuture(sender, commandLabel));
} else if (args.length > 3) {
final double x = args[1].startsWith("~") ? target.getLocation().getX() + (args[1].length() > 1 ? Double.parseDouble(args[1].substring(1)) : 0) : Double.parseDouble(args[1]);
@@ -21,7 +21,7 @@ public class Commandtpoffline extends EssentialsCommand {
final Location logout = target.getLogoutLocation();
if (logout == null) {
user.sendTl("teleportOfflineUnknown", target.getDisplayName());
user.sendTl("teleportOfflineUnknown", user.getDisplayName());
throw new NoChargeException();
}
@@ -38,7 +38,7 @@ public class Commandunban extends EssentialsCommand {
ess.getServer().getBanList(BanList.Type.NAME).pardon(name);
}
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.displayName();
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
ess.getLogger().log(Level.INFO, ess.getAdventureFacet().miniToLegacy(tlLiteral("playerUnbanned", senderDisplayName, name)));
ess.broadcastTl((IUser) null, "essentials.ban.notify", "playerUnbanned", senderDisplayName, name);
@@ -40,7 +40,7 @@ public class Commandunbanip extends EssentialsCommand {
}
ess.getServer().getBanList(BanList.Type.IP).pardon(ipAddress);
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.displayName();
final String senderDisplayName = sender.isPlayer() ? sender.getPlayer().getDisplayName() : Console.DISPLAY_NAME;
ess.getLogger().log(Level.INFO, ess.getAdventureFacet().miniToLegacy(tlLiteral("playerUnbanIpAddress", senderDisplayName, ipAddress)));
ess.broadcastTl((IUser) null, "essentials.banip.notify", "playerUnbanIpAddress", senderDisplayName, ipAddress);
@@ -30,16 +30,18 @@ public class Commandweather extends EssentialsCommand {
isStorm = args[0].equalsIgnoreCase("storm");
}
final World world = user.getWorld();
ess.scheduleGlobalDelayedTask(() -> {
final World world = user.getWorld();
if (args.length > 1) {
if (args.length > 1) {
world.setStorm(isStorm);
world.setWeatherDuration(Integer.parseInt(args[1]) * 20);
user.sendTl(isStorm ? "weatherStormFor" : "weatherSunFor", world.getName(), args[1]);
return;
}
world.setStorm(isStorm);
world.setWeatherDuration(Integer.parseInt(args[1]) * 20);
user.sendTl(isStorm ? "weatherStormFor" : "weatherSunFor", world.getName(), args[1]);
return;
}
world.setStorm(isStorm);
user.sendTl(isStorm ? "weatherStorm" : "weatherSun", world.getName());
user.sendTl(isStorm ? "weatherStorm" : "weatherSun", world.getName());
});
}
@Override
@@ -54,14 +56,16 @@ public class Commandweather extends EssentialsCommand {
throw new TranslatableException("weatherInvalidWorld", args[0]);
}
if (args.length > 2) {
ess.scheduleLocationDelayedTask(world.getSpawnLocation(), () -> {
if (args.length > 2) {
world.setStorm(isStorm);
world.setWeatherDuration(Integer.parseInt(args[2]) * 20);
sender.sendTl(isStorm ? "weatherStormFor" : "weatherSunFor", world.getName(), args[2]);
return;
}
world.setStorm(isStorm);
world.setWeatherDuration(Integer.parseInt(args[2]) * 20);
sender.sendTl(isStorm ? "weatherStormFor" : "weatherSunFor", world.getName(), args[2]);
return;
}
world.setStorm(isStorm);
sender.sendTl(isStorm ? "weatherStorm" : "weatherSun", world.getName());
sender.sendTl(isStorm ? "weatherStorm" : "weatherSun", world.getName());
});
}
@Override
@@ -56,7 +56,7 @@ public abstract class EssentialsCommand implements IEssentialsCommand {
//noinspection InfiniteLoopStatement
while (true) {
final String baseKey = name + "CommandUsage" + i;
addUsageString(tlLiteral(baseKey), baseKey + "Description");
addUsageString(tlLiteral(baseKey), tlLiteral(baseKey + "Description"));
i++;
}
} catch (MissingResourceException ignored) {
@@ -1,9 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.IEssentialsModule;
import com.earth2me.essentials.User;
import net.ess3.api.IEssentials;
import org.bukkit.Server;
import java.util.ArrayList;
@@ -12,7 +10,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashSet;
public class EssentialsTreeCommand extends EssentialsCommand {
private final Map<String, EssentialsTreeNode> nodes = new HashMap<>();
@@ -35,22 +32,6 @@ public class EssentialsTreeCommand extends EssentialsCommand {
node.setParent(this);
}
@Override
public void setEssentials(final IEssentials ess) {
super.setEssentials(ess);
for (final EssentialsTreeNode node : new HashSet<>(nodes.values())) {
node.setEssentials(ess);
}
}
@Override
public void setEssentialsModule(final IEssentialsModule module) {
super.setEssentialsModule(module);
for (final EssentialsTreeNode node : new HashSet<>(nodes.values())) {
node.setEssentialsModule(module);
}
}
public void runDefault(final User user, final String commandLabel) throws Exception {
runDefault(user.getSource(), commandLabel);
}
@@ -37,7 +37,7 @@ public class VersionCommand extends EssentialsTreeNode {
);
public VersionCommand() {
super("version", "ver");
super("version");
}
@Override
@@ -171,16 +171,6 @@ public class UserConfigHolder {
this.godmode = value;
}
private boolean flymode = false;
public boolean flyMode() {
return this.flymode;
}
public void flyMode(final boolean value) {
this.flymode = value;
}
private boolean muted = false;
public boolean muted() {
@@ -32,7 +32,7 @@ public final class EconomyLayers {
}
public static void onEnable(final Essentials ess) {
ess.scheduleSyncDelayedTask(() -> {
ess.scheduleInitTask(() -> {
serverStarted = true;
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
if (!plugin.isEnabled()) {
@@ -122,12 +122,7 @@ public interface IMessageRecipient extends MailSender {
/**
* States that the message was <b>NOT</b> received as a result of the message pre-send event being cancelled.
*/
EVENT_CANCELLED,
/**
* States that the message was <b>NOT</b> delivered as a result of the sender being muted. The message may
* still have been shown to social spies.
*/
SENDER_MUTED;
EVENT_CANCELLED;
/**
* Returns whether this response is a success. In other words equal to {@link #SUCCESS} or {@link #SUCCESS_BUT_AFK}
@@ -91,18 +91,6 @@ public class SimpleMessageRecipient implements IMessageRecipient {
}
message = preSendEvent.getMessage();
final User senderUser = getUser(this);
// A muted player must not have their message delivered to the recipient. However, social spies
// may still observe the attempted message (see the socialspy-listen-muted-players setting).
// Note: PrivateMessageSentEvent is intentionally not fired here so the message is not relayed
// elsewhere (e.g. to Discord) as though it had actually been delivered.
if (senderUser != null && senderUser.isMuted()) {
sendSocialSpy(recipient, message, true);
senderUser.notifyMuted();
return MessageResponse.SENDER_MUTED;
}
final MessageResponse messageResponse = recipient.onReceiveMessage(this.parent, message);
switch (messageResponse) {
case UNREACHABLE:
@@ -126,7 +114,29 @@ public class SimpleMessageRecipient implements IMessageRecipient {
sendTl("msgFormat", AdventureUtil.parsed(tlSender("meSender")), recipient.getDisplayName(), message);
// Better Social Spy
sendSocialSpy(recipient, message, false);
if (ess.getSettings().isSocialSpyMessages()) {
final User senderUser = getUser(this);
final User recipientUser = getUser(recipient);
if (senderUser != null // not null if player.
// Dont spy on chats involving socialspy exempt players
&& !senderUser.isAuthorized("essentials.chat.spy.exempt")
&& recipientUser != null && !recipientUser.isAuthorized("essentials.chat.spy.exempt")) {
final String senderName = ess.getSettings().isSocialSpyDisplayNames() ? getDisplayName() : getName();
final String recipientName = ess.getSettings().isSocialSpyDisplayNames() ? recipient.getDisplayName() : recipient.getName();
for (final User onlineUser : ess.getOnlineUsers()) {
if (onlineUser.isSocialSpyEnabled()
// Don't send socialspy messages to message sender/receiver to prevent spam
&& !onlineUser.equals(senderUser)
&& !onlineUser.equals(recipient)) {
if (senderUser.isMuted() && ess.getSettings().getSocialSpyListenMutedPlayers()) {
onlineUser.sendComponent(ess.getAdventureFacet().deserializeMiniMessage(tlSender("socialSpyMutedPrefix") + tlLiteral("socialSpyMsgFormat", senderName, recipientName, message)));
} else {
onlineUser.sendComponent(ess.getAdventureFacet().deserializeMiniMessage(tlLiteral("socialSpyPrefix") + tlLiteral("socialSpyMsgFormat", senderName, recipientName, message)));
}
}
}
}
}
break;
}
// If the message was a success, set this sender's reply-recipient to the current recipient.
@@ -140,45 +150,6 @@ public class SimpleMessageRecipient implements IMessageRecipient {
return messageResponse;
}
/**
* Shows a private message to all online social spies, unless either party is exempt from being spied on.
*
* @param recipient the recipient of the private message
* @param message the message that was sent
* @param muted whether the sender is muted; muted messages are only shown when
* {@code socialspy-listen-muted-players} is enabled and use a distinct prefix
*/
private void sendSocialSpy(final IMessageRecipient recipient, final String message, final boolean muted) {
if (!ess.getSettings().isSocialSpyMessages()) {
return;
}
if (muted && !ess.getSettings().getSocialSpyListenMutedPlayers()) {
return;
}
final User senderUser = getUser(this);
final User recipientUser = getUser(recipient);
// Don't spy on chats involving socialspy exempt players.
if (senderUser == null // not null if player.
|| senderUser.isAuthorized("essentials.chat.spy.exempt")
|| recipientUser == null
|| recipientUser.isAuthorized("essentials.chat.spy.exempt")) {
return;
}
final String senderName = ess.getSettings().isSocialSpyDisplayNames() ? getDisplayName() : getName();
final String recipientName = ess.getSettings().isSocialSpyDisplayNames() ? recipient.getDisplayName() : recipient.getName();
final String prefix = muted ? tlSender("socialSpyMutedPrefix") : tlLiteral("socialSpyPrefix");
for (final User onlineUser : ess.getOnlineUsers()) {
if (onlineUser.isSocialSpyEnabled()
// Don't send socialspy messages to message sender/receiver to prevent spam
&& !onlineUser.equals(senderUser)
&& !onlineUser.equals(recipient)) {
onlineUser.sendComponent(ess.getAdventureFacet().deserializeMiniMessage(prefix + tlLiteral("socialSpyMsgFormat", senderName, recipientName, message)));
}
}
}
@Override
public MessageResponse onReceiveMessage(final IMessageRecipient sender, final String message) {
if (!isReachable()) {
@@ -28,13 +28,6 @@ public interface IPermissionsHandler {
boolean hasPermission(Player base, String node);
default boolean hasPermissionCached(Player base, String node) {
return hasPermission(base, node);
}
default void invalidatePermissionCache(UUID uuid) {
}
// Does not check for * permissions
boolean isPermissionSet(Player base, String node);
@@ -105,16 +105,6 @@ public class PermissionsHandler implements IPermissionsHandler {
return handler.hasPermission(base, node);
}
@Override
public boolean hasPermissionCached(final Player base, final String node) {
return handler.hasPermissionCached(base, node);
}
@Override
public void invalidatePermissionCache(final UUID uuid) {
handler.invalidatePermissionCache(uuid);
}
@Override
public boolean isPermissionSet(final Player base, final String node) {
return handler.isPermissionSet(base, node);
@@ -7,22 +7,17 @@ import net.luckperms.api.context.ContextCalculator;
import net.luckperms.api.context.ContextConsumer;
import net.luckperms.api.context.ContextSet;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.event.EventSubscription;
import net.luckperms.api.event.user.UserDataRecalculateEvent;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.query.QueryOptions;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import java.util.logging.Level;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -30,8 +25,6 @@ public class LuckPermsHandler extends ModernVaultHandler {
private LuckPerms luckPerms;
private Essentials ess;
private CombinedCalculator calculator;
private final Map<UUID, Map<String, Boolean>> permissionCache = new ConcurrentHashMap<>();
private EventSubscription<UserDataRecalculateEvent> recalculateSubscription;
@Override
public void registerContext(final String context, final Function<User, Iterable<String>> calculator, final Supplier<Iterable<String>> suggestions) {
@@ -48,30 +41,6 @@ public class LuckPermsHandler extends ModernVaultHandler {
this.luckPerms.getContextManager().unregisterCalculator(this.calculator);
this.calculator = null;
}
if (this.recalculateSubscription != null) {
this.recalculateSubscription.close();
this.recalculateSubscription = null;
}
this.permissionCache.clear();
}
@Override
public boolean hasPermissionCached(final Player base, final String node) {
final UUID uuid = base.getUniqueId();
final Map<String, Boolean> userCache = permissionCache.computeIfAbsent(uuid, k -> new ConcurrentHashMap<>());
return userCache.computeIfAbsent(node, k -> hasPermission(base, node));
}
@Override
public void invalidatePermissionCache(final UUID uuid) {
invalidateCache(uuid);
}
public void invalidateCache(final UUID uuid) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "Invalidating permission cache for " + uuid);
}
permissionCache.remove(uuid);
}
@Override
@@ -93,13 +62,7 @@ public class LuckPermsHandler extends ModernVaultHandler {
@Override
public boolean isOfflinePermissionSet(UUID uuid, String node) {
// Try to get the user from LuckPerms' cache first to avoid blocking the main
// thread with a database lookup. In the context of a player join (e.g.
// PlayerServerFullCheckEvent), the user should already be loaded.
net.luckperms.api.model.user.User user = this.luckPerms.getUserManager().getUser(uuid);
if (user == null) {
user = this.luckPerms.getUserManager().loadUser(uuid).join();
}
final net.luckperms.api.model.user.User user = this.luckPerms.getUserManager().loadUser(uuid).join();
if (user == null) {
return false;
}
@@ -114,11 +77,6 @@ public class LuckPermsHandler extends ModernVaultHandler {
if (provider != null) {
this.luckPerms = provider.getProvider();
this.ess = ess;
this.recalculateSubscription = this.luckPerms.getEventBus().subscribe(
ess,
UserDataRecalculateEvent.class,
event -> invalidateCache(event.getUser().getUniqueId())
);
}
return luckPerms != null && super.tryProvider(ess);
}
@@ -21,8 +21,10 @@ public class SignDisposal extends EssentialsSign {
@Override
protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) {
final String customTitle = (sign.getLine(1) + " " + sign.getLine(2) + " " + sign.getLine(3)).trim();
final String title = customTitle.isEmpty() ? ess.getAdventureFacet().miniToLegacy(player.playerTl("disposal")) : customTitle;
String title = (sign.getLine(1) + " " + sign.getLine(2) + " " + sign.getLine(3)).trim();
if (title.isEmpty()) {
title = player.playerTl("disposal");
}
player.getBase().openInventory(ess.getServer().createInventory(player.getBase(), 36, title));
return true;
}
@@ -97,9 +97,8 @@ public class SignTrade extends EssentialsSign {
stack = stack.clone();
stack.setAmount(amount);
final Trade store = new Trade(stack, ess);
addAmount(sign, 2, store, ess, true);
store.charge(player);
addAmount(sign, 2, store, ess, false);
store.charge(player);
return store;
}
}
@@ -288,7 +288,7 @@ public class KeywordReplacer implements IText {
for (final String groupName : playerList.keySet()) {
final List<User> groupUsers = playerList.get(groupName);
if (groupUsers != null && !groupUsers.isEmpty()) {
outputList.put(groupName, ess.getAdventureFacet().miniToLegacy(PlayerList.listUsers(ess, groupUsers, " ")));
outputList.put(groupName, PlayerList.listUsers(ess, groupUsers, " "));
}
}
@@ -346,7 +346,7 @@ public class KeywordReplacer implements IText {
}
break;
case TPS:
replacer = NumberUtil.formatDouble(ess.getTimer().getAverageTPS());
replacer = NumberUtil.formatDouble(20d); //todo
break;
case UPTIME:
replacer = DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime());
@@ -380,10 +380,8 @@ public class KeywordReplacer implements IText {
}
if (this.replaceSpacesWithUnderscores) {
// Don't replace spaces with underscores in commands, and skip escaping
// for USERNAME since Minecraft names never contain spaces but can
// contain underscores that must stay literal (e.g. player:{USERNAME}).
if (!line.startsWith("/") && validKeyword != KeywordType.USERNAME) {
// Don't replace spaces with underscores in command nor escape underscores.
if (!line.startsWith("/")) {
replacer = replacer.replace("_", "\\_").replaceAll("\\s", "_");
}
}
@@ -102,13 +102,6 @@ public class ModernUserMap extends CacheLoader<UUID, User> implements IUserMap {
@Override
public User getUser(final Player base) {
final UUID uuid = base.getUniqueId();
final User cachedUser = userCache.getIfPresent(uuid);
if (cachedUser != null && cachedUser.getBase() == base) {
uuidCache.updateCache(uuid, base.getName());
return cachedUser;
}
final User user = loadUncachedUser(base);
userCache.put(user.getUUID(), user);
debugLogCache(user);
@@ -167,10 +167,6 @@ public final class LocationUtil {
return isBlockDamaging(world, x, y, z) || isBlockAboveAir(ess, world, x, y, z);
}
private static boolean isBlockUnsafe(IEssentials ess, final World world, final int x, final int y, final int z, final int maxY) {
return y >= maxY || isBlockUnsafe(ess, world, x, y, z);
}
public static boolean isBlockDamaging(final World world, final int x, final int y, final int z) {
final Material block = world.getBlockAt(x, y, z).getType();
final Material below = world.getBlockAt(x, y - 1, z).getType();
@@ -228,9 +224,7 @@ public final class LocationUtil {
final World world = loc.getWorld();
final int worldMinY = worldInfoProvider.getMinHeight(world);
final int worldLogicalY = worldInfoProvider.getLogicalHeight(world);
final int worldMaxY = ess.getSettings().isConsiderWorldHeightForTeleportSafety() && loc.getBlockY() < worldLogicalY
? worldLogicalY
: worldInfoProvider.getMaxHeight(world);
final int worldMaxY = loc.getBlockY() < worldLogicalY ? worldLogicalY : worldInfoProvider.getMaxHeight(world);
int x = loc.getBlockX();
int y = (int) Math.round(loc.getY());
int z = loc.getBlockZ();
@@ -248,12 +242,12 @@ public final class LocationUtil {
break;
}
}
if (isBlockUnsafe(ess, world, x, y, z, worldMaxY)) {
if (isBlockUnsafe(ess, world, x, y, z)) {
x = Math.round(loc.getX()) == origX ? x - 1 : x + 1;
z = Math.round(loc.getZ()) == origZ ? z - 1 : z + 1;
}
int i = 0;
while (isBlockUnsafe(ess, world, x, y, z, worldMaxY)) {
while (isBlockUnsafe(ess, world, x, y, z)) {
i++;
if (i >= VOLUME.length) {
x = origX;
@@ -265,14 +259,14 @@ public final class LocationUtil {
y = NumberUtil.constrainToRange(origY + VOLUME[i].y, worldMinY, worldMaxY);
z = origZ + VOLUME[i].z;
}
while (isBlockUnsafe(ess, world, x, y, z, worldMaxY)) {
while (isBlockUnsafe(ess, world, x, y, z)) {
y += 1;
if (y >= worldMaxY) {
x += 1;
break;
}
}
while (isBlockUnsafe(ess, world, x, y, z, worldMaxY)) {
while (isBlockUnsafe(ess, world, x, y, z)) {
y -= 1;
if (y <= worldMinY + 1) {
x += 1;
@@ -52,7 +52,7 @@ public final class MaterialUtil {
BEDS = EnumUtil.getAllMatching(Material.class, "BED", "BED_BLOCK", "WHITE_BED", "ORANGE_BED",
"MAGENTA_BED", "LIGHT_BLUE_BED", "YELLOW_BED", "LIME_BED", "PINK_BED", "GRAY_BED",
"LIGHT_GRAY_BED", "CYAN_BED", "PURPLE_BED", "BLUE_BED", "BROWN_BED", "GREEN_BED",
"RED_BED", "BLACK_BED", "STRAW_BED");
"RED_BED", "BLACK_BED");
BANNERS = EnumUtil.getAllMatching(Material.class, "BANNER", "WHITE_BANNER",
"ORANGE_BANNER", "MAGENTA_BANNER", "LIGHT_BLUE_BANNER", "YELLOW_BANNER", "LIME_BANNER",
@@ -86,8 +86,7 @@ public final class MaterialUtil {
"OAK_SIGN", "SPRUCE_SIGN",
"CRIMSON_SIGN", "WARPED_SIGN",
"MANGROVE_SIGN", "CHERRY_SIGN",
"BAMBOO_SIGN", "PALE_OAK_SIGN",
"POPLAR_SIGN");
"BAMBOO_SIGN", "PALE_OAK_SIGN");
WALL_SIGNS = EnumUtil.getAllMatching(Material.class, "WALL_SIGN",
"ACACIA_WALL_SIGN", "BIRCH_WALL_SIGN",
@@ -95,24 +94,21 @@ public final class MaterialUtil {
"OAK_WALL_SIGN", "SPRUCE_WALL_SIGN",
"CRIMSON_WALL_SIGN", "WARPED_WALL_SIGN",
"MANGROVE_WALL_SIGN", "CHERRY_WALL_SIGN",
"BAMBOO_WALL_SIGN", "PALE_OAK_WALL_SIGN",
"POPLAR_WALL_SIGN");
"BAMBOO_WALL_SIGN", "PALE_OAK_WALL_SIGN");
HANGING_SIGNS = EnumUtil.getAllMatching(Material.class, "ACACIA_HANGING_SIGN", "BIRCH_HANGING_SIGN",
"DARK_OAK_HANGING_SIGN", "JUNGLE_HANGING_SIGN",
"OAK_HANGING_SIGN", "SPRUCE_HANGING_SIGN",
"CRIMSON_HANGING_SIGN", "WARPED_HANGING_SIGN",
"MANGROVE_HANGING_SIGN", "CHERRY_HANGING_SIGN",
"BAMBOO_HANGING_SIGN", "PALE_OAK_HANGING_SIGN",
"POPLAR_HANGING_SIGN");
"BAMBOO_HANGING_SIGN", "PALE_OAK_HANGING_SIGN");
HANGING_WALL_SIGNS = EnumUtil.getAllMatching(Material.class, "ACACIA_WALL_HANGING_SIGN", "BIRCH_WALL_HANGING_SIGN",
"DARK_OAK_WALL_HANGING_SIGN", "JUNGLE_WALL_HANGING_SIGN",
"OAK_WALL_HANGING_SIGN", "SPRUCE_WALL_HANGING_SIGN",
"CRIMSON_WALL_HANGING_SIGN", "WARPED_WALL_HANGING_SIGN",
"MANGROVE_WALL_HANGING_SIGN", "CHERRY_WALL_HANGING_SIGN",
"BAMBOO_WALL_HANGING_SIGN", "PALE_OAK_WALL_HANGING_SIGN",
"POPLAR_WALL_HANGING_SIGN");
"BAMBOO_WALL_HANGING_SIGN", "PALE_OAK_WALL_HANGING_SIGN");
}
private MaterialUtil() {
@@ -1,23 +0,0 @@
package com.earth2me.essentials.utils;
import io.papermc.lib.environments.PaperEnvironment;
import io.papermc.lib.features.asyncchunks.AsyncChunksPaper_15;
import io.papermc.lib.features.asyncteleport.AsyncTeleportPaper_13;
import io.papermc.lib.features.bedspawnlocation.BedSpawnLocationPaper;
import io.papermc.lib.features.chunkisgenerated.ChunkIsGeneratedApiExists;
/**
* A PaperLib environment for Paper servers whose version PaperLib cannot read.
* <p>
* PaperLib 1.0.6 expects a single digit major version in {@code Bukkit#getVersion()}, so it reads 26.x as version 0 and
* selects its synchronous fallbacks for chunk loading, teleporting and bed lookups. All of those exist on every Paper
* version that reports a year based version.
*/
public class ModernPaperEnvironment extends PaperEnvironment {
public ModernPaperEnvironment() {
asyncChunksHandler = new AsyncChunksPaper_15();
asyncTeleportHandler = new AsyncTeleportPaper_13();
isGeneratedHandler = new ChunkIsGeneratedApiExists();
bedSpawnLocationHandler = new BedSpawnLocationPaper();
}
}
@@ -16,13 +16,12 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPOutputStream;
public final class PasteUtil {
private static final String PASTE_URL = "https://pastes.dev/";
private static final String PASTE_UPLOAD_URL = "https://api.pastes.dev/post";
private static volatile ExecutorService PASTE_EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
private static final ExecutorService PASTE_EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
private static final Gson GSON = new Gson();
private PasteUtil() {
@@ -36,7 +35,7 @@ public final class PasteUtil {
*/
public static CompletableFuture<PasteResult> createPaste(List<PasteFile> pages) {
final CompletableFuture<PasteResult> future = new CompletableFuture<>();
getExecutor().submit(() -> {
PASTE_EXECUTOR_SERVICE.submit(() -> {
try {
final HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection();
connection.setRequestMethod("POST");
@@ -82,28 +81,6 @@ public final class PasteUtil {
return future;
}
private static synchronized ExecutorService getExecutor() {
if (PASTE_EXECUTOR_SERVICE == null || PASTE_EXECUTOR_SERVICE.isShutdown() || PASTE_EXECUTOR_SERVICE.isTerminated()) {
PASTE_EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
}
return PASTE_EXECUTOR_SERVICE;
}
public static synchronized void shutdownExecutor() {
final ExecutorService exec = PASTE_EXECUTOR_SERVICE;
if (exec == null) {
return;
}
exec.shutdown();
try {
if (!exec.awaitTermination(5, TimeUnit.SECONDS)) {
exec.shutdownNow();
}
} catch (final InterruptedException ignored) {
exec.shutdownNow();
}
}
public static class PasteFile {
private final String name;
private final String contents;
@@ -18,21 +18,11 @@ public final class StringUtil {
private StringUtil() {
}
private static final Pattern WINDOWS_RESERVED = Pattern.compile("^(con|prn|aux|nul|com[0-9]|lpt[0-9])$");
//Used to clean file names before saving to disk
public static String sanitizeFileName(final String name) {
return INVALIDFILECHARS.matcher(name.toLowerCase(Locale.ENGLISH)).replaceAll("_");
}
/**
* Returns true if the given name is a Windows reserved filename (e.g. CON, NUL, AUX).
* Using these as file names on Windows will hang or crash the server.
*/
public static boolean isReservedFileName(final String name) {
return WINDOWS_RESERVED.matcher(name.toLowerCase(Locale.ENGLISH)).matches();
}
//Used to clean strings/names before saving as filenames/permissions
public static String safeString(final String string) {
if (string == null) {
@@ -40,20 +40,17 @@ public final class VersionUtil {
public static final BukkitVersion v1_19_R01 = BukkitVersion.fromString("1.19-R0.1-SNAPSHOT");
public static final BukkitVersion v1_19_4_R01 = BukkitVersion.fromString("1.19.4-R0.1-SNAPSHOT");
public static final BukkitVersion v1_20_1_R01 = BukkitVersion.fromString("1.20.1-R0.1-SNAPSHOT");
public static final BukkitVersion v1_20_4_R01 = BukkitVersion.fromString("1.20.4-R0.1-SNAPSHOT");
public static final BukkitVersion v1_20_6_R01 = BukkitVersion.fromString("1.20.6-R0.1-SNAPSHOT");
public static final BukkitVersion v1_21_R01 = BukkitVersion.fromString("1.21-R0.1-SNAPSHOT");
public static final BukkitVersion v1_21_3_R01 = BukkitVersion.fromString("1.21.3-R0.1-SNAPSHOT");
public static final BukkitVersion v1_21_5_R01 = BukkitVersion.fromString("1.21.5-R0.1-SNAPSHOT");
public static final BukkitVersion v1_21_8_R01 = BukkitVersion.fromString("1.21.8-R0.1-SNAPSHOT");
public static final BukkitVersion v1_21_11_R01 = BukkitVersion.fromString("1.21.11-R0.1-SNAPSHOT");
public static final BukkitVersion v26_1_R01 = BukkitVersion.fromString("26.1.2-R0.1-SNAPSHOT");
public static final BukkitVersion v26_2_R01 = BukkitVersion.fromString("26.2-R0.1-SNAPSHOT");
public static final BukkitVersion v26_3_R01 = BukkitVersion.fromString("26.3-R0.1-SNAPSHOT");
private static final Set<BukkitVersion> supportedVersions = ImmutableSet.of(v1_8_8_R01, v1_9_4_R01, v1_10_2_R01, v1_11_2_R01, v1_12_2_R01, v1_13_2_R01, v1_14_4_R01, v1_15_2_R01, v1_16_5_R01, v1_17_1_R01, v1_18_2_R01, v1_19_4_R01, v1_20_6_R01, v1_21_11_R01, v26_1_R01, v26_2_R01, v26_3_R01);
private static final Set<BukkitVersion> supportedVersions = ImmutableSet.of(v1_8_8_R01, v1_9_4_R01, v1_10_2_R01, v1_11_2_R01, v1_12_2_R01, v1_13_2_R01, v1_14_4_R01, v1_15_2_R01, v1_16_5_R01, v1_17_1_R01, v1_18_2_R01, v1_19_4_R01, v1_20_6_R01, v1_21_11_R01);
public static final boolean PRE_FLATTENING = VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01);
public static final boolean FOLIA;
public static final List<String> officialPlugins = Arrays.asList(
"EssentialsAntiBuild",
@@ -79,6 +76,15 @@ public final class VersionUtil {
private static final String PFX = make("8(;4>`");
static {
boolean isFolia;
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
isFolia = true;
} catch (Throwable ignored) {
isFolia = false;
}
FOLIA = isFolia;
final ImmutableMap.Builder<String, SupportStatus> builder = new ImmutableMap.Builder<>();
// Leaf, yet another "High Performance" fork of Paper. Not supported by EssentialsX.
@@ -179,7 +185,7 @@ public final class VersionUtil {
}
}
if (!isSupportedVersion(getServerBukkitVersion())) {
if (!supportedVersions.contains(getServerBukkitVersion())) {
return supportStatus = SupportStatus.OUTDATED;
}
@@ -192,39 +198,14 @@ public final class VersionUtil {
return supportStatusClass;
}
/**
* Checks if a version is considered supported, either by exact match in the
* supported versions set, or by matching the base version (major.minor.patch)
* of a supported version. This handles both the new PaperMC versioning scheme
* (which omits the Bukkit revision suffix) and development builds that report
* versions like {@code 26.1-rc-3.build.8-alpha}.
*/
private static boolean isSupportedVersion(final BukkitVersion version) {
if (supportedVersions.contains(version)) {
return true;
}
// Check if this version matches a supported base version.
// This covers Paper versions (no -R0.1-SNAPSHOT suffix) and
// dev variants (snapshot/pre-release/RC/Paper builds).
for (final BukkitVersion supported : supportedVersions) {
if (version.equalsBaseVersion(supported)) {
return true;
}
}
return false;
}
public static final class BukkitVersion implements Comparable<BukkitVersion> {
private static final Pattern VERSION_PATTERN = Pattern.compile("^(\\d+)\\.(\\d+)\\.?([0-9]*)?(?:-snapshot-(\\d+))?(?:-pre-?(\\d+))?(?:-rc-?(\\d+))?(?:\\.build\\.(\\d+)(?:-([a-z]+))?)?(?:-?R?([\\d.]+))?(?:(?:\\.local)?-SNAPSHOT)?");
private static final Pattern LEGACY_SNAPSHOT_PATTERN = Pattern.compile("^(\\d{2})w(\\d{2})([a-z])(?:-?R?([\\d.]+))?(?:-SNAPSHOT)?");
private static final Pattern VERSION_PATTERN = Pattern.compile("^(\\d+)\\.(\\d+)\\.?([0-9]*)?(?:-pre(\\d))?(?:-rc(\\d+))?(?:-?R?([\\d.]+))?(?:-SNAPSHOT)?");
private static final Pattern SNAPSHOT_PATTERN = Pattern.compile("^(\\d{2})w(\\d{2})([a-z])(?:-?R?([\\d.]+))?(?:-SNAPSHOT)?");
private final int major;
private final int minor;
private final int snapshotRelease;
private final int preRelease;
private final int releaseCandidate;
private final int paperBuild;
private final String releaseChannel;
private final int patch;
private final double revision;
@@ -233,33 +214,27 @@ public final class VersionUtil {
private final int snapshotWeek;
private final char snapshotLetter;
private BukkitVersion(final int major, final int minor, final int patch, final double revision, final int snapshotRelease, final int preRelease, final int releaseCandidate, final int paperBuild, final String releaseChannel) {
private BukkitVersion(final int major, final int minor, final int patch, final double revision, final int preRelease, final int releaseCandidate) {
this.major = major;
this.minor = minor;
this.patch = patch;
this.revision = revision;
this.snapshotRelease = snapshotRelease;
this.preRelease = preRelease;
this.releaseCandidate = releaseCandidate;
this.paperBuild = paperBuild;
this.releaseChannel = releaseChannel;
this.snapshot = false;
this.snapshotYear = -1;
this.snapshotWeek = -1;
this.snapshotLetter = '\0';
}
private BukkitVersion(final int major, final int minor, final int patch, final double revision, final int snapshotRelease, final int preRelease, final int releaseCandidate, final int paperBuild, final String releaseChannel,
private BukkitVersion(final int major, final int minor, final int patch, final double revision, final int preRelease, final int releaseCandidate,
final boolean snapshot, final int snapshotYear, final int snapshotWeek, final char snapshotLetter) {
this.major = major;
this.minor = minor;
this.patch = patch;
this.revision = revision;
this.snapshotRelease = snapshotRelease;
this.preRelease = preRelease;
this.releaseCandidate = releaseCandidate;
this.paperBuild = paperBuild;
this.releaseChannel = releaseChannel;
this.snapshot = snapshot;
this.snapshotYear = snapshotYear;
this.snapshotWeek = snapshotWeek;
@@ -272,11 +247,11 @@ public final class VersionUtil {
// Try standard release format first
Matcher matcher = VERSION_PATTERN.matcher(string);
if (matcher.matches()) {
return from(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(9), matcher.group(4), matcher.group(5), matcher.group(6), matcher.group(7), matcher.group(8));
return from(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(6), matcher.group(4), matcher.group(5));
}
// Try snapshot format (e.g., 25w32a-R0.1-SNAPSHOT)
final Matcher snapshotMatcher = LEGACY_SNAPSHOT_PATTERN.matcher(string);
final Matcher snapshotMatcher = SNAPSHOT_PATTERN.matcher(string);
if (snapshotMatcher.matches()) {
final int year = Integer.parseInt(snapshotMatcher.group(1));
final int week = Integer.parseInt(snapshotMatcher.group(2));
@@ -294,29 +269,24 @@ public final class VersionUtil {
}
matcher = VERSION_PATTERN.matcher(v1_16_1_R01.toString());
Preconditions.checkArgument(matcher.matches(), string + " is not in valid version format. e.g. 1.8.8-R0.1");
return from(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(9), matcher.group(4), matcher.group(5), matcher.group(6), matcher.group(7), matcher.group(8));
return from(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(6), matcher.group(4), matcher.group(5));
}
private static BukkitVersion from(final String major, final String minor, String patch, String revision, String snapshotRelease, String preRelease, String releaseCandidate, String paperBuild, final String releaseChannel) {
private static BukkitVersion from(final String major, final String minor, String patch, String revision, String preRelease, String releaseCandidate) {
if (patch == null || patch.isEmpty()) patch = "0";
if (revision == null || revision.isEmpty()) revision = "0";
if (snapshotRelease == null || snapshotRelease.isEmpty()) snapshotRelease = "-1";
if (preRelease == null || preRelease.isEmpty()) preRelease = "-1";
if (releaseCandidate == null || releaseCandidate.isEmpty()) releaseCandidate = "-1";
if (paperBuild == null || paperBuild.isEmpty()) paperBuild = "-1";
return new BukkitVersion(Integer.parseInt(major),
Integer.parseInt(minor),
Integer.parseInt(patch),
Double.parseDouble(revision),
Integer.parseInt(snapshotRelease),
Integer.parseInt(preRelease),
Integer.parseInt(releaseCandidate),
Integer.parseInt(paperBuild),
releaseChannel);
Integer.parseInt(releaseCandidate));
}
private static BukkitVersion fromSnapshot(final int year, final int week, final char letter, final double revision) {
return new BukkitVersion(-1, -1, -1, revision, -1, -1, -1, -1, null, true, year, week, letter);
return new BukkitVersion(-1, -1, -1, revision, -1, -1, true, year, week, letter);
}
public boolean isHigherThan(final BukkitVersion o) {
@@ -359,37 +329,10 @@ public final class VersionUtil {
return releaseCandidate;
}
public int getSnapshotRelease() {
return snapshotRelease;
}
public int getPaperBuild() {
return paperBuild;
}
public String getReleaseChannel() {
return releaseChannel;
}
public boolean isSnapshot() {
return snapshot;
}
/**
* Checks if this version has the same base version (major, minor, and patch)
* as the given version, ignoring development specifiers and Bukkit metadata.
* Revision is ignored because Paper versions do not include the Bukkit
* revision suffix (e.g. {@code -R0.1-SNAPSHOT}).
*/
public boolean equalsBaseVersion(final BukkitVersion other) {
if (this.snapshot || other.snapshot) {
return false;
}
return this.major == other.major &&
this.minor == other.minor &&
this.patch == other.patch;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
@@ -410,9 +353,7 @@ public final class VersionUtil {
minor == that.minor &&
patch == that.patch &&
revision == that.revision &&
snapshotRelease == that.snapshotRelease &&
preRelease == that.preRelease &&
releaseCandidate == that.releaseCandidate;
preRelease == that.preRelease;
}
@Override
@@ -420,7 +361,7 @@ public final class VersionUtil {
if (snapshot) {
return Objects.hashCode("snapshot", snapshotYear, snapshotWeek, snapshotLetter, revision);
}
return Objects.hashCode(major, minor, patch, revision, snapshotRelease, preRelease, releaseCandidate);
return Objects.hashCode(major, minor, patch, revision, preRelease, releaseCandidate);
}
@Override
@@ -432,31 +373,15 @@ public final class VersionUtil {
if (patch != 0) {
sb.append(".").append(patch);
}
if (snapshotRelease != -1) {
sb.append("-snapshot-").append(snapshotRelease);
}
if (preRelease != -1) {
sb.append("-pre-").append(preRelease);
sb.append("-pre").append(preRelease);
}
if (releaseCandidate != -1) {
sb.append("-rc-").append(releaseCandidate);
}
if (paperBuild != -1) {
sb.append(".build.").append(paperBuild);
if (releaseChannel != null) {
sb.append("-").append(releaseChannel);
}
sb.append("-rc").append(releaseCandidate);
}
return sb.append("-R").append(revision).toString();
}
private static int compareDevSpecifier(final int a, final int b) {
if (a == b) return 0;
if (a == -1) return 1;
if (b == -1) return -1;
return Integer.compare(a, b);
}
@Override
public int compareTo(final BukkitVersion o) {
// Snapshots are always considered the most recent
@@ -492,20 +417,18 @@ public final class VersionUtil {
} else if (patch > o.patch) {
return 1;
} else { // equal patch
// For dev specifiers, -1 means absent (final release) and
// sorts HIGHER than any present value: snapshot < pre < rc < release
int cmp = compareDevSpecifier(snapshotRelease, o.snapshotRelease);
if (cmp != 0) return cmp;
cmp = compareDevSpecifier(preRelease, o.preRelease);
if (cmp != 0) return cmp;
cmp = compareDevSpecifier(releaseCandidate, o.releaseCandidate);
if (cmp != 0) return cmp;
if (paperBuild < o.paperBuild) {
if (preRelease < o.preRelease) {
return -1;
} else if (paperBuild > o.paperBuild) {
} else if (preRelease > o.preRelease) {
return 1;
} else {
return Double.compare(revision, o.revision);
} else { // equal prerelease
if (releaseCandidate < o.releaseCandidate) {
return -1;
} else if (releaseCandidate > o.releaseCandidate) {
return 1;
} else { // equal release candidate
return Double.compare(revision, o.revision);
}
}
}
}
@@ -8,12 +8,6 @@ import org.bukkit.event.HandlerList;
* <p>
* For other cases where the player's vanish status changes, you should listen on PlayerJoinEvent and
* check with {@link IUser#isVanished()}.
*
* <b>WARNING: The values of {@link #getAffected()} and {@link #getController()} are inverted due to
* a long-standing parameter swap. {@link #getAffected()} returns the command sender (null for console),
* and {@link #getController()} returns the player whose vanish status changed.</b>
*
* @see <a href="https://github.com/EssentialsX/Essentials/issues/2604">#2604</a>
*/
public class VanishStatusChangeEvent extends StatusChangeEvent {
private static final HandlerList handlers = new HandlerList();
@@ -13,13 +13,11 @@ public class AsyncUserDataLoadEvent extends Event {
private final IUser user;
private final String joinMessage;
private final boolean firstJoin;
public AsyncUserDataLoadEvent(IUser user, String joinMessage, boolean firstJoin) {
public AsyncUserDataLoadEvent(IUser user, String joinMessage) {
super(true);
this.user = user;
this.joinMessage = joinMessage;
this.firstJoin = firstJoin;
}
/**
@@ -36,18 +34,6 @@ public class AsyncUserDataLoadEvent extends Event {
return joinMessage;
}
/**
* Whether this is the first time EssentialsX has seen this player join.
* <p>
* This is determined from EssentialsX's own user data rather than {@link org.bukkit.OfflinePlayer#hasPlayedBefore()},
* which is unreliable on modern server platforms that persist player data during the login/configuration phase.
*
* @return {@code true} if this is the player's first recorded join, otherwise {@code false}.
*/
public boolean isFirstJoin() {
return firstJoin;
}
@Override
public HandlerList getHandlers() {
return handlers;
@@ -1,59 +0,0 @@
package net.essentialsx.api.v2.events;
import com.earth2me.essentials.CommandSource;
import com.google.common.base.Preconditions;
import net.ess3.api.IUser;
import org.bukkit.Bukkit;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import java.math.BigDecimal;
/**
* Fired when a transaction (e.g. /pay) is about to be handled.
*/
public class PreTransactionEvent extends TransactionEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
public PreTransactionEvent(final CommandSource requester, final IUser target, final BigDecimal amount) {
super(!Bukkit.isPrimaryThread(), requester, target, amount);
}
/**
* Sets the amount to be subtracted from the requester's balance.
* <p>
* Note: Changing this amount will not verify the requester actually has enough balance to complete the transaction.
* @param decimal the new amount
*/
public void setAmount(final BigDecimal decimal) {
Preconditions.checkNotNull(decimal, "decimal cannot be null");
Preconditions.checkArgument(decimal.compareTo(BigDecimal.ZERO) >= 0, "decimal cannot be negative");
this.amount = decimal;
}
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* If this event should be cancelled. If cancelled, no messages will be displayed to the users involved.
* @param cancelled whether this event should be cancelled
*/
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -16,19 +16,15 @@ public class TransactionEvent extends Event {
private final CommandSource requester;
private final IUser target;
protected BigDecimal amount;
private final BigDecimal amount;
protected TransactionEvent(boolean async, CommandSource requester, IUser target, BigDecimal amount) {
super(async);
public TransactionEvent(CommandSource requester, IUser target, BigDecimal amount) {
super(!Bukkit.isPrimaryThread());
this.requester = requester;
this.target = target;
this.amount = amount;
}
public TransactionEvent(CommandSource requester, IUser target, BigDecimal amount) {
this(!Bukkit.isPrimaryThread(), requester, target, amount);
}
/**
* @return the user who initiated the transaction
*/
+4 -79
View File
@@ -34,7 +34,7 @@ ops-name-color: '4'
nickname-prefix: '~'
# The maximum length allowed in nicknames. The nickname prefix is not included in this.
max-nick-length: 16
max-nick-length: 15
# The regex pattern used to determine if a requested nickname should be allowed for use.
# If the requested nickname does not match this pattern, the nickname will be rejected.
@@ -51,10 +51,6 @@ nick-blacklist:
# For example, if "&6Notch" has 7 characters (2 are part of a color code), a length of 5 is used when this option is set to true.
ignore-colors-in-max-nick-length: false
# When this option is enabled, any nickname set by a player will be reset when their Minecraft account name changes.
# This prevents old nicknames (including RGB-formatted ones) from persisting after a name change.
reset-nick-on-name-change: false
# When this option is enabled, display names for hidden players will not be shown. This prevents players from being
# able to see that they are online while vanished.
hide-displayname-in-vanish: true
@@ -99,10 +95,6 @@ force-disable-teleport-safety: false
# safe location. If you'd like players to be teleported to a safe location all of the time, set this option to true.
force-safe-teleport-location: false
# When teleporting to an unsafe location, should Essentials consider the world's logical height when finding a safe destination?
# This prevents safety checks from moving players above the Nether roof unless the requested destination is already above it.
consider-world-height-for-teleport-safety: true
# Consider water blocks as "safe", therefore allowing players to teleport
# using commands such as /home or /spawn to a location that is occupied by water blocks.
is-water-safe: false
@@ -499,7 +491,7 @@ auto-afk: 300
auto-afk-timeout: -1
# A list of commands to be executed instead of kicking the player once the
# threshold defined above in 'afk-auto-timeout' is reached. If this list is empty
# threshold defined above in 'afk-auto-timeout' is reached. If this list is empty
# and 'afk-auto-timeout' is not set to -1, Essentials will default to
# kicking the player once they reach the timeout threshold.
#
@@ -535,9 +527,6 @@ cancel-afk-on-move: true
# Should Essentials automatically remove AFK status when a player sends a chat message?
cancel-afk-on-chat: true
# Should Essentials automatically remove AFK status when a player uses a fishing rod?
cancel-afk-on-fish: true
# Should AFK players be ignored when other players are trying to sleep?
# When this setting is false, players won't be able to skip the night if some players are AFK.
# Players with the permission 'essentials.sleepingignored' will always be ignored.
@@ -908,8 +897,8 @@ baltop-requirements:
minimum-balance: 0
minimum-playtime: 0
# Limit the number of cached balance top entries.
# Recommended for servers with a large number of players, as it reduces memory usage.
# Limit the number of cached balance top entries.
# Recommended for servers with a large number of players, as it reduces memory usage.
# Set to -1 to disable the limit.
baltop-entry-limit: -1
@@ -1149,70 +1138,6 @@ protect:
witch: false
horse: false
phantom: false
zombified_piglin: false
mooshroom: false
snow_golem: false
rabbit: false
guardian: false
elder_guardian: false
endermite: false
shulker: false
polar_bear: false
stray: false
husk: false
wither_skeleton: false
zombie_villager: false
skeleton_horse: false
zombie_horse: false
donkey: false
mule: false
llama: false
evoker: false
vex: false
vindicator: false
illusioner: false
parrot: false
turtle: false
cod: false
salmon: false
pufferfish: false
tropical_fish: false
dolphin: false
drowned: false
cat: false
fox: false
panda: false
pillager: false
ravager: false
trader_llama: false
wandering_trader: false
bee: false
hoglin: false
piglin: false
piglin_brute: false
strider: false
zoglin: false
axolotl: false
glow_squid: false
goat: false
allay: false
frog: false
tadpole: false
warden: false
camel: false
sniffer: false
armadillo: false
bogged: false
breeze: false
creaking: false
happy_ghast: false
copper_golem: false
camel_husk: false
nautilus: false
zombie_nautilus: false
parched: false
sulfur_cube: false
cushion: false
# The maximum height a creeper can explode. -1 allows them to explode everywhere.
# Set 'creeper-explosion' above to true if you want to disable creeper explosions completely.
File diff suppressed because it is too large. Load diff
Loaded 100 of 202 files, more files were not shown because too many files have changed in this diff. Show more