Compare commits

..
Author SHA1 Message Date
Wyatt Childers ca7967085b Implement region namespaces 2020-01-19 14:10:33 -05:00
wizjany b835ee39d5 Check water/lava placement from dispensers on edge of region.
Fixes WORLDGUARD-4161.
2020-01-03 23:11:56 -05:00
Pieter12345 4a7552e6be Prevent pushing pistons across region borders
Pistons are classified as not pushable regardless of their state, causing WorldGuard to not protect against them moving. This commit fixes that.
2020-01-01 13:53:09 -05:00
Joo200 c6c0fc9d74 Fixed failed checkstyle gradle task 2020-01-01 13:53:01 -05:00
wizjany f43a4eaad8 Add spawn-protection overlap check when defining regions.
Update cached username on login.
Bump WorldEdit dep version.
2019-12-19 15:42:34 -05:00
JOO200 abfa5cb6a5 bee nests can be modified by right click (like beehives) 2019-12-16 14:08:04 -05:00
JOO200 05f7d68705 Use Paper-API 1.15 as Dependency 2019-12-16 14:08:04 -05:00
wizjany 9adac4f239 Initial 1.15 stuff.
Materials is not really cross-version compatible. Really could do with
some rewriting at some point.
2019-12-10 23:48:50 -05:00
wizjany c5355adb4b Back to snapshot. 2019-11-22 23:51:25 -05:00
wizjany fb37342b3c Release 7.0.1. 2019-11-22 23:43:05 -05:00
wizjany 1fd94a3655 Switch blacklist to drilldown since bstats doesn't support bar charts.
See https://github.com/Bastian/bStats/issues/67

Also update blacklist example txt with correct names.
2019-11-17 18:13:45 -05:00
wizjany c413cf4123 Remove pointless iterable. 2019-11-17 18:13:45 -05:00
wizjany 87162acf11 Switch blacklist stat to entry counts. 2019-11-17 18:13:45 -05:00
wizjany 2c14acc28c Add some custom charts to bStats.
Should give a good view of feature usage, especially some badly
supported features like SQL and chest protection.
2019-11-17 18:13:45 -05:00
wizjany 26477406f1 Fix pistons flag not applying to sticky pistons pulling. 2019-10-11 22:12:03 -04:00
wizjany 121b34ecb9 Add applicable regions section to /wg report. 2019-10-06 13:09:08 -04:00
wizjany 3ebaaf9c8b Add /rg toggle-bypass command to turn off region bypass temporarily.
Makes it easier to test things without op/de-op, switching ranks, etc
all the time.
2019-10-06 12:17:07 -04:00
wizjany 4c9812db04 Fix exit-deny-message using wrong region set on enderpearl/chorus-fruit. 2019-10-06 12:17:07 -04:00
wizjany e792dd6f98 Workaround colors on newlines of string flags issue in text lib.
Also fix newline lookbehind replacement, and only replace color macros
in string flags.
2019-10-06 12:17:07 -04:00
wizjany d410e1f84e Re-arrange messages in (re)define commands.
Only send messages after successful add.
2019-10-06 12:17:07 -04:00
wizjany d07f95952d Causes only track blocks, not locations. 2019-09-26 20:24:11 -04:00
wizjany cb9ab3a7b2 Check creeper-explosion flag for all entity damage, not just players. 2019-09-26 10:38:02 -04:00
wizjany 1c3cf02ebd BlockMultiPlace has an immutable state list.
Fixes WORLDGUARD-4143.
2019-09-22 15:16:57 -04:00
wizjany fc0f7acab5 Fix infinite loop in addowner checks.
Fixes WORLDGUARD-4138.
2019-09-22 14:28:38 -04:00
wizjany 20db92541b Make use of BlockFertilizeEvent, various BlockState lists.
Only mostly tested to work. BlockFertilize unfortunately doesn't let
us cancel the preceding stuff like StructureGrow and item use.

Also workaround Bukkit sending 2 events for trampling.
2019-09-18 15:43:36 -04:00
wizjany 5fca3b3c3d Track causes when players ignite creepers.
Fixes WORLDGUARD-4136.
2019-09-13 17:34:37 -04:00
wizjany c633a2d070 Cover some more plants as crop-growth.
Note that spigot doesn't throw events for bamboo yet, so this only
applies to sugar canes and cacti at the moment. Should work if spigot
implements BlockGrowEvent for cacti though.

Fixes WORLDGUARD-4137.
2019-09-13 17:20:51 -04:00
wizjany effbd62e68 Ignore hopper minecarts with the ignore hopper setting. 2019-09-13 16:43:27 -04:00
wizjany 056eaa6587 Teleport async on Paper. 2019-09-13 16:42:35 -04:00
wizjany cb2c0870ec List is not a valid cause. Each element is its own cause.
Fixes WORLDGUARD-4140.

Specifically, fixes not being able to break lilypads while in a boat,
even through the player would normally be able to.

Note that slowdown is client-side and getting stuck is due to Spigot
not updating the client when the break is cancelled, which are unrelated
to this issue (and not fixable by us).
2019-09-13 16:32:28 -04:00
wizjany 179c324c80 Apparently world names are allowed to have spaces. 2019-08-18 23:43:57 -04:00
wizjany 96d15d6dbf Only store existing per-player time/weather in handlers.
Fixes WORLDGUARD-4124.

This will fix various issues with logging in to regions with these flags
set and then moving out of them, or when moving between two adjacent
regions with the flags set and then moving out.
2019-08-18 12:00:50 -04:00
wizjany 120d2e223d Extract/half-fix addowner checks.
Max-region-count-for-player is super bork.

Fixes WORLDGUARD-4129.
2019-08-18 10:39:56 -04:00
wizjany 70ea6bad6e Some cleanup for flag command. 2019-08-18 10:38:07 -04:00
wizjany e59d61e1cf Extract NumberFlag for suggestions, make FlagHelper prettier in console. 2019-08-06 23:08:10 -04:00
wizjany bbed280f62 Update docs links to point to enginehub.
Also don't allow block-place/block-break setting from flag helper.
2019-08-06 21:50:05 -04:00
wizjany f165ae3d95 Back to snapshot. 2019-08-06 00:12:41 -04:00
wizjany 124898ec91 7.0.1 RC 2. 2019-08-06 00:12:26 -04:00
wizjany ba32d24363 Merge pull request #414 from EngineHub/feature/paper
Add some Paper-specific features
2019-08-05 23:49:04 -04:00
wizjany 0bba822295 Link ender crystal entity <-> material. 2019-08-03 18:10:54 -04:00
wizjany 7538af2686 TippedArrow again. 2019-08-02 16:34:26 -04:00
wizjany 48922118b1 Fix fireworks, protect by default (this is a behavioral change).
Add regions.use-paper-entity-origin setting, false by default because
it can have some weird implications.
2019-08-01 23:47:27 -04:00
wizjany 14fe2d0e79 Use Paper player profiles if available.
Also fall back to caching to memory if SQLite can't be linked.
This is a common issue with (bad) server hosts who mount /tmp as noexec,
which causes sqlite's native binaries to fail to link.
2019-08-01 20:24:34 -04:00
wizjany 11a1ac6742 User paper firework tracking. 2019-08-01 20:24:33 -04:00
wizjany c5bfdcb0e6 Use PaperLib for some performance enhancements. 2019-08-01 20:24:32 -04:00
wizjany 93dae282b2 Apparently some plugins do weird things with falling blocks. 2019-08-01 20:12:58 -04:00
wizjany 3468e3d47e Handful of small fixes.
* Fix material loading from config requiring minecraft: namespace.
* Fix disallowed-lightning blocks. Lightning entities are weird.
* Fix /wg reload overwriting config changes.
* General around thread usage/naming/shutdown. If anyone was actually
  making their own managers/indices you deserve to break.
2019-07-31 22:53:20 -04:00
wizjany b7ad0257b7 Remove legacy potion code. 2019-07-30 18:44:24 -04:00
wizjany 070f6e005f Merge pull request #415 from EngineHub/kotlin-dsl
Migrate gradle to kotlin dsl.
2019-07-30 16:56:46 -04:00
wizjany cc3f4d4d44 Relocate squirrelid in source, fix flyway shading. 2019-07-30 09:44:19 -04:00
wizjany 21e65be110 Fix poms, remove bukkit lib project since it's currently unused. 2019-07-29 23:41:38 -04:00
wizjany 61494fd76e Migrate gradle to kotlin dsl. 2019-07-29 23:25:13 -04:00
wizjany 556b638d04 Switch build badge to TC.
And remove dead wiki links.
2019-07-29 11:34:18 -04:00
wizjany 825b3a3f36 Save defaults to config file. 2019-07-27 22:40:03 -04:00
wizjany afe042ef4d Add option for resetting fall distance when void falling teleport is on.
reset-fall-on-void-teleport, defaults to false. (I can't remember if
old WG 6 behavior was to do this or not...?)
2019-07-27 21:57:49 -04:00
wizjany 4044e2b122 Ender crystal explosions can't be cause tracked. 2019-07-26 22:51:19 -04:00
wizjany aa4137822f Fix sleep flag. 2019-07-24 14:35:42 -04:00
wizjany f37acd3de6 Whitelist player->player interacts.
As noted before, any more specific events should still be blocked (such
as potion use).
2019-07-23 20:13:12 -04:00
wizjany b0e4cf148b ItemElytra extends ItemArmor... 2019-07-19 20:45:16 -04:00
wizjany 248ffd0ba8 Maybe fix travis. 2019-07-18 14:54:13 -04:00
wizjany 3272759f25 Check waterlogged blocks when emptying buckets.
Fixes WORLDGUARD-4119.
2019-07-17 07:45:31 -04:00
wizjany 456a16591b Handle UseEntity player->player events as PvP.
Fixes WORLDGUARD-4118.
Tell me if this breaks other intended behaviors somehow.
2019-07-16 18:48:57 -04:00
wizjany 79f6635b8a Make /wg profile text more clear.
This patch dedicated to @phoenix616.
2019-07-16 18:42:48 -04:00
wizjany 1f362bef59 Minecarts spawn in the clicked (rail) block. 2019-07-09 07:47:54 -04:00
wizjany 63209d1174 Null-check for last commit. 2019-07-07 01:22:04 -04:00
wizjany f546700189 Allow interact-whitelist for entities with matching item types. 2019-07-06 11:02:36 -04:00
wizjany 35e0db36d3 Workaround for sign dying issue.
Signs still get dyed even if you deny using dye.
2019-07-03 09:53:11 -04:00
wizjany ab7751e046 Unfix WORLDGUARD-3360.
There's a reason this wasn't done before. This is fundamentally broken.
2019-07-02 23:08:50 -04:00
wizjany a9cd23c6ef Don't replace in comments and strings when you refactor... 2019-07-02 17:39:21 -04:00
wizjany 8ca01b37a4 Add config to disable villagers getting zapped to witches.
"weather.disable-villager-witchification"
2019-06-30 19:58:10 -04:00
wizjany aa8997aeca Add TP button to /rg list where applicable. 2019-06-30 11:37:50 -04:00
wizjany b757fcc88b Send CUI changes when using /rg select. 2019-06-27 08:06:09 -04:00
wizjany 7593e1a01c Initial update to 1.14. 2019-06-25 22:12:18 -04:00
106 changed files with 2964 additions and 1216 deletions

No files matched your search

+1
View File
@@ -1,4 +1,5 @@
language: java
dist: trusty
jdk:
- oraclejdk8
notifications:
+43
View File
@@ -1,5 +1,48 @@
# Changelog
## 7.0.1
* Add `/rg toggle-bypass` command which temporarily turns off region bypassing until used again.
* More improvements to `/rg flag` and `/rg flags` commands.
* Fix some checks for adding owners to unclaimed regions.
* Fix an issue with time-/weather-lock flags when logging in to a region with the flag set.
* Fix cause tracking in vehicles (incl. breaking lilypads in a boat)
* Use async teleports on Paper.
* Include hopper minecarts in the ignore hoppers config setting.
* Add sugar cane and cacti to the crop-growth flag. Bamboo is also included pending Spigot throwing an event for it.
* Specifically track when players ignite creepers with flint and steel.
* Fix fuzziness when using bonemeal near a protected region.
* Fix color codes not applying in greeting, etc flags when placed after a newline (\n).
* Add applicable region information to `/wg report`.
* Fix pistons flag not applying to sticky pistons pulling blocks.
* Add some custom metrics for bStats.
* Everything in the RC/beta changelog below.
## 7.0.1 RC 2 (inc. beta 1)
* Due to breaking changes in important Bukkit API, this is not compatible with MC 1.13!
* Update to MC 1.14. Adds protection for new blocks, etc.
* To allow players to read from lecterns, but not take the book, flag interact allow, and then flag chest-access -g nonmembers deny.
* Add ravager-grief flag.
* Fix overprotection of unsaddled pigs with the ride flag.
* Fix lava fire defaulting to off (won't change existing configs).
* Fix damaged/chipped anvils not respecting use flag like regular anvils.
* Add on-equip blacklist event. Note that it is overprotective due to deficiencies in Bukkit API.
* Update WorldEdit CUI when using /rg select.
* Add config option to disable villagers getting zapped into witches. ("weather.disable-villager-witchification")
* Add entity support to interact-whitelist config option (use the Material of the corresponding item).
* Fix vehicle-place protecting the rails at the very top of region boundaries incorrectly.
* Fix for emptying buckets on waterloggable blocks.
* Whitelist all player -> player interactions (previously was spammy in pvp).
* Fix sleep flag not protecting against explosions in nether/end.
* Add config for the teleport-on-void to reset fall distance.
* Fix config options taking material lists requiring "minecraft:" namespace.
* Fix disallowed-lightning-blocks situationally not working.
* Fix errors that occurred when plugins used falling block entities with non-item materials.
* Add special support for Paper servers (papermc.io): Paper's API allows us to track who launched fireworks.
* Fireworks are now protected by default. On Paper servers, members can use them by default (to deal damage),
on non-Paper servers, flag firework-damage allow to revert to old behavior (everyone can deal damage with fireworks by default).
* Misc performance enhancements for Paper servers.
* Add 'regions.use-paper-entity-origin' as an experimental setting (default off) for Paper servers. Enabling it will make non-player entities be treated as members of the place they spawned, instead of their current location when flags are checked.
## 7.0.0
* Added support for MC 1.13, dropped support for previous versions.
* Added lots of interactive text in e.g. `/rg info` command.
+16
View File
@@ -0,0 +1,16 @@
WorldGuard, a suite of tools for Minecraft
Copyright (C) sk89q <http://www.sk89q.com>
Copyright (C) WorldGuard team and contributors
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
+3 -4
View File
@@ -22,8 +22,7 @@ Compiling
---------
The project is written for Java 8 and our build process makes use of
[Gradle](http://gradle.org). Detailed compilation information
[can be found on the wiki](http://wiki.sk89q.com/wiki/WorldGuard/Development#Compiling).
[Gradle](http://gradle.org).
Dependencies are automatically handled by Gradle.
@@ -43,5 +42,5 @@ Links
* [Discord](https://discord.gg/enginehub)
* [IRC channel](https://webchat.esper.net/?join=sk89q) (#sk89q on irc.esper.net)
* [Issue tracker](https://dev.enginehub.org/issues/WORLDGUARD)
* [Continuous integration](http://builds.enginehub.org) [![Build Status](https://travis-ci.org/EngineHub/WorldGuard.svg?branch=master)](https://travis-ci.org/EngineHub/WorldGuard)
* [End-user documentation](https://worldguard.readthedocs.io/en/latest/) / [Older Wiki](http://wiki.sk89q.com/wiki/WorldGuard)
* [Continuous integration](http://builds.enginehub.org) [![Build Status](https://ci.enginehub.org/app/rest/builds/buildType:bt11,branch:master/statusIcon.svg)](http://ci.enginehub.org/viewType.html?buildTypeId=bt11&guest=1)
* [End-user documentation](https://worldguard.enginehub.org/en/latest/)
-136
View File
@@ -1,136 +0,0 @@
println """
*******************************************
You are building WorldGuard!
If you encounter trouble:
1) Read COMPILING.md if you haven't yet
2) Try running 'build' in a separate Gradle run
3) Use gradlew and not gradle
4) If you still need help, ask on IRC! irc.esper.net #sk89q
Output files will be in [subproject]/build/libs
*******************************************
"""
buildscript {
repositories {
mavenCentral()
maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" }
jcenter()
}
configurations.all {
resolutionStrategy {
force 'com.google.guava:guava:21.0'
}
}
dependencies {
classpath "com.github.jengelman.gradle.plugins:shadow:4.0.3"
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.7.5'
classpath 'org.ajoberstar:gradle-git:1.7.2'
}
}
allprojects {
group = 'com.sk89q.worldguard'
version = '7.0.1-SNAPSHOT'
}
if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost"
if (!project.hasProperty("artifactory_user")) ext.artifactory_user = "guest"
if (!project.hasProperty("artifactory_password")) ext.artifactory_password = ""
if (!project.hasProperty("gitCommitHash")) {
try {
def repo = org.ajoberstar.grgit.Grgit.open(project.file('.'))
ext.gitCommitHash = repo.head().abbreviatedId
} catch (Exception e) {
ext.gitCommitHash = "no_git_id"
}
}
apply plugin: 'com.jfrog.artifactory'
artifactory {
contextUrl = "${artifactory_contextUrl}"
publish {
repository {
repoKey = project.version.contains("SNAPSHOT") ? 'libs-snapshot-local' : 'libs-release-local'
username = "${artifactory_user}"
password = "${artifactory_password}"
maven = true
}
}
}
artifactoryPublish.skip = true
subprojects {
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'maven'
apply plugin: 'checkstyle'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'com.jfrog.artifactory'
ext.internalVersion = version + ";" + gitCommitHash
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
checkstyle.configFile = new File(rootProject.projectDir, "config/checkstyle/checkstyle.xml")
checkstyle.toolVersion = '7.6.1'
repositories {
mavenLocal()
mavenCentral()
maven { url "https://repo.spongepowered.org/maven/" }
maven { url "https://hub.spigotmc.org/nexus/content/groups/public" }
maven { url "https://maven.sk89q.com/repo/" }
maven { url "https://repo.maven.apache.org/maven2" }
}
if (JavaVersion.current().isJava8Compatible()) {
// Java 8 turns on doclint which we fail
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
}
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives jar
archives sourcesJar
archives javadocJar
}
build.dependsOn(checkstyleMain)
build.dependsOn(checkstyleTest)
build.dependsOn(sourcesJar)
build.dependsOn(javadocJar)
shadowJar {
classifier 'dist'
dependencies {
include(dependency('org.khelekore:prtree:1.5.0'))
include(dependency('com.sk89q:squirrelid:0.2.0'))
include(dependency('org.flywaydb:flyway-core:3.0'))
}
exclude 'GradleStart**'
exclude '.cache'
exclude 'LICENSE*'
}
artifactoryPublish {
publishConfigs('archives')
}
}
+26
View File
@@ -0,0 +1,26 @@
import org.ajoberstar.grgit.Grgit
logger.lifecycle("""
*******************************************
You are building WorldGuard!
If you encounter trouble:
1) Try running 'build' in a separate Gradle run
2) Use gradlew and not gradle
3) If you still need help, ask on Discord! https://discord.gg/enginehub
Output files will be in [subproject]/build/libs
*******************************************
""")
applyRootArtifactoryConfig()
if (!project.hasProperty("gitCommitHash")) {
apply(plugin = "org.ajoberstar.grgit")
ext["gitCommitHash"] = try {
(ext["grgit"] as Grgit?)?.head()?.abbreviatedId
} catch (e: Exception) {
logger.warn("Error getting commit hash", e)
"no_git_id"
}
}
+19
View File
@@ -0,0 +1,19 @@
plugins {
`kotlin-dsl`
kotlin("jvm") version embeddedKotlinVersion
}
repositories {
jcenter()
gradlePluginPortal()
}
dependencies {
implementation(gradleApi())
implementation("gradle.plugin.net.minecrell:licenser:0.4.1")
implementation("org.ajoberstar.grgit:grgit-gradle:3.1.1")
implementation("com.github.jengelman.gradle.plugins:shadow:5.1.0")
implementation("net.ltgt.apt-eclipse:net.ltgt.apt-eclipse.gradle.plugin:0.21")
implementation("net.ltgt.apt-idea:net.ltgt.apt-idea.gradle.plugin:0.21")
implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.7")
}
@@ -0,0 +1,40 @@
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.named
import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention
import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTask
private const val ARTIFACTORY_CONTEXT_URL = "artifactory_contextUrl"
private const val ARTIFACTORY_USER = "artifactory_user"
private const val ARTIFACTORY_PASSWORD = "artifactory_password"
fun Project.applyRootArtifactoryConfig() {
if (!project.hasProperty(ARTIFACTORY_CONTEXT_URL)) ext[ARTIFACTORY_CONTEXT_URL] = "http://localhost"
if (!project.hasProperty(ARTIFACTORY_USER)) ext[ARTIFACTORY_USER] = "guest"
if (!project.hasProperty(ARTIFACTORY_PASSWORD)) ext[ARTIFACTORY_PASSWORD] = ""
apply(plugin = "com.jfrog.artifactory")
configure<ArtifactoryPluginConvention> {
setContextUrl("${project.property(ARTIFACTORY_CONTEXT_URL)}")
clientConfig.publisher.run {
repoKey = when {
"${project.version}".contains("SNAPSHOT") -> "libs-snapshot-local"
else -> "libs-release-local"
}
username = "${project.property(ARTIFACTORY_USER)}"
password = "${project.property(ARTIFACTORY_PASSWORD)}"
isMaven = true
isIvy = false
}
}
tasks.named<ArtifactoryTask>("artifactoryPublish") {
isSkip = true
}
}
fun Project.applyCommonArtifactoryConfig() {
val named = tasks.named<ArtifactoryTask>("artifactoryPublish") {
publishConfigs("archives")
}
}
+18
View File
@@ -0,0 +1,18 @@
import org.gradle.api.Project
import org.gradle.kotlin.dsl.repositories
fun Project.applyCommonConfiguration() {
group = rootProject.group
version = rootProject.version
repositories {
mavenCentral()
maven { url = uri("https://maven.sk89q.com/repo/") }
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
}
configurations.all {
resolutionStrategy {
cacheChangingModulesFor(5, "minutes")
}
}
}
+12
View File
@@ -0,0 +1,12 @@
import org.gradle.api.Project
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.the
val Project.ext: ExtraPropertiesExtension
get() = extensions.getByType()
val Project.sourceSets: SourceSetContainer
get() = the<JavaPluginConvention>().sourceSets
+96
View File
@@ -0,0 +1,96 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Project
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.internal.HasConvention
import org.gradle.api.plugins.MavenRepositoryHandlerConvention
import org.gradle.api.tasks.Upload
import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getPlugin
import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.register
fun Project.applyLibrariesConfiguration() {
applyCommonConfiguration()
apply(plugin = "java-base")
apply(plugin = "maven")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "com.jfrog.artifactory")
configurations {
create("shade")
getByName("archives").extendsFrom(getByName("default"))
}
group = "${rootProject.group}.worldguard-libs"
tasks.register<ShadowJar>("jar") {
configurations = listOf(project.configurations["shade"])
archiveClassifier.set("")
dependencies {
exclude(dependency("com.google.code.findbugs:jsr305:1.3.9"))
}
relocate("com.sk89q.squirrelid", "com.sk89q.worldguard.util.profile")
}
val altConfigFiles = { artifactType: String ->
val deps = configurations["shade"].incoming.dependencies
.filterIsInstance<ModuleDependency>()
.map { it.copy() }
.map { dependency ->
dependency.artifact {
name = dependency.name
type = artifactType
extension = "jar"
classifier = artifactType
}
dependency
}
files(configurations.detachedConfiguration(*deps.toTypedArray())
.resolvedConfiguration.lenientConfiguration.artifacts
.filter { it.classifier == artifactType }
.map { zipTree(it.file) })
}
tasks.register<Jar>("sourcesJar") {
from({
altConfigFiles("sources")
})
val filePattern = Regex("(.*)com/sk89q/squirrelid((?:/|$).*)")
val textPattern = Regex("com\\.sk89q\\.squirrelid")
eachFile {
filter {
it.replaceFirst(textPattern, "com.sk89q.worldguard.util.profile")
}
path = path.replaceFirst(filePattern, "$1com/sk89q/worldguard/util/profile$2")
}
archiveClassifier.set("sources")
}
tasks.named("assemble").configure {
dependsOn("jar", "sourcesJar")
}
artifacts {
val jar = tasks.named("jar")
add("default", jar) {
builtBy(jar)
}
val sourcesJar = tasks.named("sourcesJar")
add("archives", sourcesJar) {
builtBy(sourcesJar)
}
}
tasks.register<Upload>("install") {
configuration = configurations["archives"]
(repositories as HasConvention).convention.getPlugin<MavenRepositoryHandlerConvention>().mavenInstaller {
pom.version = project.version.toString()
pom.artifactId = project.name
}
}
applyCommonArtifactoryConfig()
}
+119
View File
@@ -0,0 +1,119 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import net.minecrell.gradle.licenser.LicenseExtension
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.plugins.quality.CheckstyleExtension
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.api.tasks.testing.Test
import org.gradle.external.javadoc.CoreJavadocOptions
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getByName
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.withType
fun Project.applyPlatformAndCoreConfiguration() {
applyCommonConfiguration()
apply(plugin = "java")
apply(plugin = "eclipse")
apply(plugin = "idea")
apply(plugin = "maven")
apply(plugin = "checkstyle")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "com.jfrog.artifactory")
apply(plugin = "net.minecrell.licenser")
ext["internalVersion"] = "$version;${rootProject.ext["gitCommitHash"]}"
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
configure<CheckstyleExtension> {
configFile = rootProject.file("config/checkstyle/checkstyle.xml")
toolVersion = "7.6.1"
}
tasks.withType<Test>().configureEach {
useJUnit()
}
dependencies {
"testCompile"("junit:junit:${Versions.JUNIT}")
// TODO switch to jupiter - doesn't support abstract test classes so tests need rewriting
//"testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.JUNIT}")
//"testRuntime"("org.junit.jupiter:junit-jupiter-engine:${Versions.JUNIT}")
}
// Java 8 turns on doclint which we fail
tasks.withType<Javadoc>().configureEach {
(options as CoreJavadocOptions).addStringOption("Xdoclint:none", "-quiet")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
tasks.named("assemble").configure {
dependsOn("javadocJar")
}
artifacts {
add("archives", tasks.named("jar"))
add("archives", tasks.named("javadocJar"))
}
if (name == "worldguard-core" || name == "worldguard-bukkit") {
tasks.register<Jar>("sourcesJar") {
dependsOn("classes")
archiveClassifier.set("sources")
from(sourceSets["main"].allSource)
}
artifacts {
add("archives", tasks.named("sourcesJar"))
}
tasks.named("assemble").configure {
dependsOn("sourcesJar")
}
}
tasks.named("check").configure {
dependsOn("checkstyleMain", "checkstyleTest")
}
applyCommonArtifactoryConfig()
configure<LicenseExtension> {
header = rootProject.file("HEADER.txt")
include("**/*.java")
}
}
fun Project.applyShadowConfiguration() {
tasks.named<ShadowJar>("shadowJar") {
archiveClassifier.set("dist")
dependencies {
include(project(":worldguard-libs:core"))
//include(project(":worldguard-libs:${project.name.replace("worldguard-", "")}"))
include(project(":worldguard-core"))
relocate("org.flywaydb", "com.sk89q.worldguard.internal.flywaydb") {
include(dependency("org.flywaydb:flyway-core:3.0"))
}
relocate("com.sk89q.squirrelid", "com.sk89q.worldguard.util.profile")
}
exclude("GradleStart**")
exclude(".cache")
exclude("LICENSE*")
}
}
+7
View File
@@ -0,0 +1,7 @@
object Versions {
// const val PISTON = "0.4.3"
// const val AUTO_VALUE = "1.6.5"
const val WORLDEDIT = "7.1.0-SNAPSHOT"
const val JUNIT = "4.11"
const val SQUIRRELID = "0.2.0"
}
+4 -8
View File
@@ -7,9 +7,11 @@
<module name="FileTabCharacter"/>
<module name="SuppressionFilter">
<property name="file" value="${basedir}/config/checkstyle/suppressions.xml"/>
<property name="file" value="${config_loc}/suppressions.xml"/>
</module>
<module name="TreeWalker">
<!-- Important basics -->
<!-- <module name="PackageDeclaration"/> Unlikely that we would miss this in a PR -->
@@ -20,7 +22,7 @@
It is a bit draconian, so update as necessary!
-->
<module name="ImportControl">
<property name="file" value="${basedir}/config/checkstyle/import-control.xml"/>
<property name="file" value="${config_loc}/import-control.xml"/>
</module>
<!-- Code -->
@@ -58,10 +60,4 @@
<!-- <module name="TypeName"/> Unlikely that we would miss this in a PR -->
</module>
<!-- Require the header, something that many people forget and we hate to fix -->
<!-- You should configure the header in your IDE -->
<module name="Header">
<property name="headerFile" value="${basedir}/config/checkstyle/header.txt"/>
<property name="fileExtensions" value="java"/>
</module>
</module>
+8 -11
View File
@@ -16,24 +16,21 @@
<allow pkg="org.khelekore"/>
<allow pkg="org.flywaydb"/>
<allow pkg="org.yaml"/>
<allow pkg="org.json"/>
<allow pkg="org.enginehub.piston"/>
<subpackage name="util.profile.resolver">
<allow pkg="org.bukkit"/>
<allow pkg="io.papermc.lib"/>
<allow pkg="com.destroystokyo.paper"/>
</subpackage>
<subpackage name="bukkit">
<allow pkg="org.bukkit"/>
<allow pkg="org.bstats.bukkit"/>
<allow pkg="io.papermc.lib"/>
<allow pkg="com.destroystokyo.paper"/>
</subpackage>
<subpackage name="sponge">
<allow pkg="org.spongepowered"/>
<allow pkg="org.bstats.sponge"/>
<allow pkg="com.flowpowered"/>
</subpackage>
<subpackage name="forge">
<allow pkg="net.minecraft"/>
<allow pkg="net.minecraftforge"/>
</subpackage>
</subpackage>
</import-control>
+2
View File
@@ -0,0 +1,2 @@
group=com.sk89q.worldguard
version=7.0.2-SNAPSHOT
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-3
View File
@@ -1,3 +0,0 @@
rootProject.name = 'worldguard'
include 'worldguard-core', 'worldguard-bukkit'
+7
View File
@@ -0,0 +1,7 @@
rootProject.name = "worldguard"
include("worldguard-libs")
include("worldguard-libs:core")
include("worldguard-core")
//include("worldguard-libs:bukkit")
include("worldguard-bukkit")
-55
View File
@@ -1,55 +0,0 @@
apply plugin: 'eclipse'
apply plugin: 'idea'
repositories {
maven {
name = 'bstats repo'
url = 'https://repo.codemc.org/repository/maven-public'
}
}
dependencies {
compile project(path: ':worldguard-core', configuration: 'shadow')
api 'org.bukkit:bukkit:1.13-R0.1-SNAPSHOT'
api ('com.sk89q.worldedit:worldedit-bukkit:7.0.1-SNAPSHOT') {
exclude group: 'io.papermc', module: 'paperlib'
}
implementation ('com.sk89q:commandbook:2.3') {
exclude group: 'com.sk89q', module: 'worldedit'
exclude group: 'com.zachsthings.libcomponents'
exclude group: 'org.bukkit'
exclude group: 'net.sf.opencsv'
}
implementation 'org.bstats:bstats-bukkit:1.5'
}
processResources {
from (sourceSets.main.resources.srcDirs) {
expand project.properties
include 'plugin.yml'
}
from (sourceSets.main.resources.srcDirs) {
exclude 'plugin.yml'
}
}
jar {
manifest {
attributes("Implementation-Version": version)
}
}
shadowJar {
dependencies {
include(dependency(':worldguard-core'))
relocate ("org.bstats", "com.sk89q.worldguard.bukkit.bstats") {
include(dependency("org.bstats:bstats-bukkit:1.5"))
}
}
relocate('org.flywaydb', 'com.sk89q.worldguard.internal.flywaydb')
}
build.dependsOn(shadowJar)
+74
View File
@@ -0,0 +1,74 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.internal.HasConvention
plugins {
id("java-library")
id("net.ltgt.apt-eclipse")
id("net.ltgt.apt-idea")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
repositories {
maven {
name = "paper"
url = uri("https://papermc.io/repo/repository/maven-public/")
}
maven {
name = "bstats"
url = uri("https://repo.codemc.org/repository/maven-public")
}
}
dependencies {
"compile"(project(":worldguard-core"))
//"compile"(project(":worldguard-libs:bukkit"))
"api"("com.destroystokyo.paper:paper-api:1.15-R0.1-SNAPSHOT")
"implementation"("io.papermc:paperlib:1.0.2")
"api"("com.sk89q.worldedit:worldedit-bukkit:${Versions.WORLDEDIT}") { isTransitive = false }
"implementation"("com.sk89q:commandbook:2.3") { isTransitive = false }
"implementation"("org.bstats:bstats-bukkit:1.5")
}
tasks.named<Upload>("install") {
(repositories as HasConvention).convention.getPlugin<MavenRepositoryHandlerConvention>().mavenInstaller {
pom.whenConfigured {
dependencies.firstOrNull { dep ->
dep!!.withGroovyBuilder {
getProperty("groupId") == "com.destroystokyo.paper" && getProperty("artifactId") == "paper-api"
}
}?.withGroovyBuilder {
setProperty("groupId", "org.bukkit")
setProperty("artifactId", "bukkit")
}
}
}
}
tasks.named<Copy>("processResources") {
filesMatching("plugin.yml") {
expand("internalVersion" to project.ext["internalVersion"])
}
}
tasks.named<Jar>("jar") {
manifest {
attributes("Implementation-Version" to project.version)
}
}
tasks.named<ShadowJar>("shadowJar") {
dependencies {
relocate("org.bstats", "com.sk89q.worldguard.bukkit.bstats") {
include(dependency("org.bstats:bstats-bukkit:1.5"))
}
relocate ("io.papermc.lib", "com.sk89q.worldguard.bukkit.paperlib") {
include(dependency("io.papermc:paperlib:1.0.2"))
}
}
}
tasks.named("assemble").configure {
dependsOn("shadowJar")
}
@@ -26,6 +26,7 @@ import com.sk89q.worldguard.config.YamlConfigurationManager;
import com.sk89q.worldedit.util.report.Unreported;
import java.io.File;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -35,6 +36,7 @@ public class BukkitConfigurationManager extends YamlConfigurationManager {
@Unreported private ConcurrentMap<String, BukkitWorldConfiguration> worlds = new ConcurrentHashMap<>();
private boolean hasCommandBookGodMode;
boolean extraStats;
/**
* Construct the object.
@@ -46,6 +48,16 @@ public class BukkitConfigurationManager extends YamlConfigurationManager {
this.plugin = plugin;
}
public Collection<BukkitWorldConfiguration> getWorldConfigs() {
return worlds.values();
}
@Override
public void load() {
super.load();
this.extraStats = getConfig().getBoolean("custom-metrics-charts", true);
}
@Override
public File getDataFolder() {
return plugin.getDataFolder();
@@ -68,6 +80,7 @@ public class BukkitConfigurationManager extends YamlConfigurationManager {
for (World world : WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getWorlds()) {
get(world);
}
getConfig().save();
}
/**
@@ -24,6 +24,8 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import io.papermc.lib.PaperLib;
import org.bukkit.BanList.Type;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -53,6 +55,16 @@ public class BukkitPlayer extends com.sk89q.worldedit.bukkit.BukkitPlayer implem
return name;
}
@Override
public String getDefaultNamespace() {
// TODO: Add a per player override
boolean useNamespaces = WorldGuard.getInstance().getPlatform().getGlobalStateManager().useNamespaces;
if (useNamespaces) {
return getUniqueId().toString();
}
return null;
}
@Override
public boolean hasGroup(String group) {
return plugin.inGroup(getPlayer(), group);
@@ -120,7 +132,8 @@ public class BukkitPlayer extends com.sk89q.worldedit.bukkit.BukkitPlayer implem
@Override
public WeatherType getPlayerWeather() {
return null;
org.bukkit.WeatherType playerWeather = getPlayer().getPlayerWeather();
return playerWeather == null ? null : playerWeather == org.bukkit.WeatherType.CLEAR ? WeatherTypes.CLEAR : WeatherTypes.RAIN;
}
@Override
@@ -173,6 +186,24 @@ public class BukkitPlayer extends com.sk89q.worldedit.bukkit.BukkitPlayer implem
getPlayer().sendTitle(title, subtitle, -1, -1, -1);
}
@Override
public void resetFallDistance() {
getPlayer().setFallDistance(0);
}
@Override
public void teleport(Location location, String successMessage, String failMessage) {
PaperLib.teleportAsync(getPlayer(), BukkitAdapter.adapt(location))
.thenApply(success -> {
if (success) {
print(successMessage);
} else {
printError(failMessage);
}
return success;
});
}
@Override
public String[] getGroups() {
return plugin.getGroups(getPlayer());
@@ -97,6 +97,10 @@ public class BukkitRegionContainer extends RegionContainer {
Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, cache::invalidateAll, CACHE_INVALIDATION_INTERVAL, CACHE_INVALIDATION_INTERVAL);
}
public void shutdown() {
container.shutdown();
}
@Override
@Nullable
protected RegionManager load(World world) {
@@ -70,6 +70,7 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
public Set<PotionEffectType> blockPotions;
public TargetMatcherSet allowAllInteract;
public TargetMatcherSet blockUseAtFeet;
public boolean usePaperEntityOrigin;
/* Configuration data end */
/**
@@ -144,6 +145,8 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
blockUseAtFeet = getTargetMatchers("event-handling.emit-block-use-at-feet");
ignoreHopperMoveEvents = getBoolean("event-handling.ignore-hopper-item-move-events", false);
usePaperEntityOrigin = getBoolean("regions.use-paper-entity-origin", false);
itemDurability = getBoolean("protection.item-durability", true);
removeInfiniteStacks = getBoolean("protection.remove-infinite-stacks", false);
disableExpDrops = getBoolean("protection.disable-xp-orb-drops", false);
@@ -216,6 +219,7 @@ public class BukkitWorldConfiguration extends YamlWorldConfiguration {
teleportOnSuffocation = getBoolean("player-damage.teleport-on-suffocation", false);
disableVoidDamage = getBoolean("player-damage.disable-void-damage", false);
teleportOnVoid = getBoolean("player-damage.teleport-on-void-falling", false);
safeFallOnVoid = getBoolean("player-damage.reset-fall-on-void-teleport", false);
disableExplosionDamage = getBoolean("player-damage.disable-explosion-damage", false);
disableMobDamage = getBoolean("player-damage.disable-mob-damage", false);
disableDeathMessages = getBoolean("player-damage.disable-death-messages", false);
@@ -19,12 +19,19 @@
package com.sk89q.worldguard.bukkit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.util.profile.resolver.PaperProfileService;
import com.sk89q.worldguard.bukkit.protection.events.flags.FlagContextCreateEvent;
import com.sk89q.worldguard.bukkit.session.BukkitSessionManager;
import com.sk89q.worldguard.bukkit.util.report.PerformanceReport;
@@ -39,12 +46,21 @@ import com.sk89q.worldguard.internal.platform.WorldGuardPlatform;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.session.SessionManager;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.resolver.BukkitPlayerService;
import com.sk89q.worldguard.util.profile.resolver.CacheForwardingService;
import com.sk89q.worldguard.util.profile.resolver.CombinedProfileService;
import com.sk89q.worldguard.util.profile.resolver.HttpRepositoryService;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.permissions.Permissible;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -130,7 +146,7 @@ public class BukkitWorldGuardPlatform implements WorldGuardPlatform {
@Override
public void unload() {
configuration.unload();
regionContainer.unload();
regionContainer.shutdown();
}
@Override
@@ -228,4 +244,36 @@ public class BukkitWorldGuardPlatform implements WorldGuardPlatform {
report.add(new WorldReport());
report.add(new PerformanceReport());
}
@Override
public ProfileService createProfileService(ProfileCache profileCache) {
List<ProfileService> services = new ArrayList<>();
if (PaperLib.isPaper()) {
// Paper has a shared cache
services.add(PaperProfileService.getInstance());
} else {
services.add(BukkitPlayerService.getInstance());
}
services.add(HttpRepositoryService.forMinecraft());
return new CacheForwardingService(new CombinedProfileService(services),
profileCache);
}
@Nullable
@Override
public ProtectedRegion getSpawnProtection(World world) {
if (world instanceof BukkitWorld) {
org.bukkit.World bWorld = ((BukkitWorld) world).getWorld();
if (bWorld.getUID().equals(Bukkit.getServer().getWorlds().get(0).getUID())) {
int radius = Bukkit.getServer().getSpawnRadius();
if (radius > 0) {
BlockVector3 spawnLoc = BukkitAdapter.asBlockVector(bWorld.getSpawnLocation());
return new ProtectedCuboidRegion("__spawn_protection__",
spawnLoc.subtract(radius, 0, radius).withY(world.getMinimumPoint().getY()),
spawnLoc.add(radius, 0, radius).withY(world.getMaxY()));
}
}
}
return null;
}
}
@@ -20,6 +20,7 @@
package com.sk89q.worldguard.bukkit;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import com.sk89q.bukkit.util.CommandsManagerRegistration;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
@@ -35,9 +36,7 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.commands.GeneralCommands;
import com.sk89q.worldguard.commands.ProtectionCommands;
import com.sk89q.worldguard.commands.ToggleCommands;
import com.sk89q.worldguard.blacklist.Blacklist;
import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.bukkit.listener.BlacklistListener;
import com.sk89q.worldguard.bukkit.listener.BlockedPotionsListener;
@@ -63,8 +62,16 @@ import com.sk89q.worldguard.bukkit.listener.WorldRulesListener;
import com.sk89q.worldguard.bukkit.session.BukkitSessionManager;
import com.sk89q.worldguard.bukkit.util.Events;
import com.sk89q.worldguard.bukkit.util.logging.ClassSourceValidator;
import com.sk89q.worldguard.commands.GeneralCommands;
import com.sk89q.worldguard.commands.ProtectionCommands;
import com.sk89q.worldguard.commands.ToggleCommands;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.registry.SimpleFlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.file.DirectoryYamlDriver;
import com.sk89q.worldguard.protection.managers.storage.sql.SQLDriver;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.util.logging.RecordMessagePrefixer;
@@ -84,6 +91,8 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarFile;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
@@ -205,7 +214,51 @@ public class WorldGuardPlugin extends JavaPlugin {
((SimpleFlagRegistry) WorldGuard.getInstance().getFlagRegistry()).setInitialized(true);
// Enable metrics
new Metrics(this);
final Metrics metrics = new Metrics(this);
if (metrics.isEnabled() && platform.getGlobalStateManager().extraStats) {
setupCustomCharts(metrics);
}
}
private void setupCustomCharts(Metrics metrics) {
metrics.addCustomChart(new Metrics.SingleLineChart("region_count", () ->
platform.getRegionContainer().getLoaded().stream().mapToInt(RegionManager::size).sum()));
metrics.addCustomChart(new Metrics.SimplePie("region_driver", () -> {
RegionDriver driver = platform.getGlobalStateManager().selectedRegionStoreDriver;
return driver instanceof DirectoryYamlDriver ? "yaml" : driver instanceof SQLDriver ? "sql" : "unknown";
}));
metrics.addCustomChart(new Metrics.DrilldownPie("blacklist", () -> {
int empty = 0;
Map<String, Integer> blacklistMap = new HashMap<>();
Map<String, Integer> whitelistMap = new HashMap<>();
for (BukkitWorldConfiguration worldConfig : platform.getGlobalStateManager().getWorldConfigs()) {
Blacklist blacklist = worldConfig.getBlacklist();
if (blacklist != null && !blacklist.isEmpty()) {
Map<String, Integer> target = blacklist.isWhitelist() ? whitelistMap : blacklistMap;
int floor = ((blacklist.getItemCount() - 1) / 10) * 10;
String range = floor >= 100 ? "101+" : (floor + 1) + " - " + (floor + 10);
target.merge(range, 1, Integer::sum);
} else {
empty++;
}
}
Map<String, Map<String, Integer>> blacklistCounts = new HashMap<>();
Map<String, Integer> emptyMap = new HashMap<>();
emptyMap.put("empty", empty);
blacklistCounts.put("empty", emptyMap);
blacklistCounts.put("blacklist", blacklistMap);
blacklistCounts.put("whitelist", whitelistMap);
return blacklistCounts;
}));
metrics.addCustomChart(new Metrics.SimplePie("chest_protection", () ->
"" + platform.getGlobalStateManager().getWorldConfigs().stream().anyMatch(cfg -> cfg.signChestProtection)));
metrics.addCustomChart(new Metrics.SimplePie("build_permissions", () ->
"" + platform.getGlobalStateManager().getWorldConfigs().stream().anyMatch(cfg -> cfg.buildPermissions)));
metrics.addCustomChart(new Metrics.SimplePie("custom_flags", () ->
"" + (WorldGuard.getInstance().getFlagRegistry().size() > Flags.INBUILT_FLAGS.size())));
metrics.addCustomChart(new Metrics.SimplePie("custom_handlers", () ->
"" + (WorldGuard.getInstance().getPlatform().getSessionManager().customHandlersRegistered())));
}
@Override
@@ -22,8 +22,19 @@ package com.sk89q.worldguard.bukkit.cause;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import com.sk89q.worldguard.bukkit.internal.WGMetadata;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.entity.*;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle;
import org.bukkit.metadata.Metadatable;
import javax.annotation.Nullable;
@@ -31,6 +42,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -249,8 +261,16 @@ public final class Cause {
addAll(((TNTPrimed) o).getSource());
} else if (o instanceof Projectile) {
addAll(((Projectile) o).getShooter());
} else if (o instanceof Firework && PaperLib.isPaper()) {
UUID spawningUUID = ((Firework) o).getSpawningEntity();
if (spawningUUID != null) {
Entity spawningEntity = Bukkit.getEntity(spawningUUID);
if (spawningEntity != null) {
addAll(spawningEntity);
}
}
} else if (o instanceof Vehicle) {
addAll(((Vehicle) o).getPassengers());
((Vehicle) o).getPassengers().forEach(this::addAll);
} else if (o instanceof AreaEffectCloud) {
indirect = true;
addAll(((AreaEffectCloud) o).getSource());
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.event.block;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldguard.bukkit.cause.Cause;
@@ -28,12 +29,15 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.event.Event;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -44,7 +48,8 @@ import javax.annotation.Nullable;
abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
private final World world;
private final List<Block> blocks;
private List<Block> blocks;
private final List<BlockState> blockStates;
private final Material effectiveMaterial;
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
@@ -55,6 +60,18 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
this.world = world;
this.blocks = blocks;
this.effectiveMaterial = effectiveMaterial;
this.blockStates = null;
}
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<BlockState> blocks) {
super(originalEvent, cause);
checkNotNull(world);
checkNotNull(blocks);
checkArgument(!blocks.isEmpty());
this.world = world;
this.blockStates = blocks;
this.blocks = null;
this.effectiveMaterial = blocks.get(0).getType();
}
protected AbstractBlockEvent(@Nullable Event originalEvent, Cause cause, Block block) {
@@ -86,6 +103,9 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
* @return a list of affected block
*/
public List<Block> getBlocks() {
if (blocks == null) { // be lazy here because we often don't call getBlocks internally, just filter
blocks = blockStates.stream().map(BlockState::getBlock).collect(Collectors.toList());
}
return blocks;
}
@@ -99,15 +119,21 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
* @return true if one or more blocks were filtered out
*/
public boolean filter(Predicate<Location> predicate, boolean cancelEventOnFalse) {
boolean hasRemoval = false;
return blocks == null
? filterInternal(blockStates, BlockState::getLocation, predicate, cancelEventOnFalse)
: filterInternal(blocks, Block::getLocation, predicate, cancelEventOnFalse);
}
Iterator<Block> it = blocks.iterator();
private <B> boolean filterInternal(List<B> blockList, Function<B, Location> locFunc,
Predicate<Location> predicate, boolean cancelEventOnFalse) {
boolean hasRemoval = false;
Iterator<B> it = blockList.iterator();
while (it.hasNext()) {
if (!predicate.test(it.next().getLocation())) {
if (!predicate.test(locFunc.apply(it.next()))) {
hasRemoval = true;
if (cancelEventOnFalse) {
getBlocks().clear();
blockList.clear();
setCancelled(true);
break;
} else {
@@ -115,7 +141,6 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
}
}
}
return hasRemoval;
}
@@ -147,7 +172,7 @@ abstract class AbstractBlockEvent extends DelegateEvent implements BulkEvent {
@Override
public Result getResult() {
if (blocks.isEmpty()) {
if (blocks == null ? blockStates.isEmpty() : blocks.isEmpty()) {
return Result.DENY;
}
return super.getResult();
@@ -24,6 +24,7 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
@@ -40,6 +41,10 @@ public class PlaceBlockEvent extends AbstractBlockEvent {
private static final HandlerList handlers = new HandlerList();
public PlaceBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<BlockState> blocks) {
super(originalEvent, cause, world, blocks);
}
public PlaceBlockEvent(@Nullable Event originalEvent, Cause cause, World world, List<Block> blocks, Material effectiveMaterial) {
super(originalEvent, cause, world, blocks, effectiveMaterial);
}
@@ -21,12 +21,26 @@ package com.sk89q.worldguard.bukkit.listener;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.cause.Cause;
import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.config.WorldConfiguration;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.protection.DelayedRegionOverlapAssociation;
import com.sk89q.worldguard.protection.association.Associables;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.regions.RegionQuery;
import io.papermc.lib.PaperLib;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
/**
@@ -67,7 +81,7 @@ class AbstractListener implements Listener {
*
* @return the configuration
*/
protected ConfigurationManager getConfig() {
protected static ConfigurationManager getConfig() {
return WorldGuard.getInstance().getPlatform().getGlobalStateManager();
}
@@ -77,7 +91,7 @@ class AbstractListener implements Listener {
* @param world The world to get the configuration for.
* @return The configuration for {@code world}
*/
protected WorldConfiguration getWorldConfig(World world) {
protected static WorldConfiguration getWorldConfig(World world) {
return getConfig().get(world);
}
@@ -87,7 +101,7 @@ class AbstractListener implements Listener {
* @param player The player to get the wold from
* @return The {@link WorldConfiguration} for the player's world
*/
protected WorldConfiguration getWorldConfig(LocalPlayer player) {
protected static WorldConfiguration getWorldConfig(LocalPlayer player) {
return getWorldConfig((World) player.getExtent());
}
@@ -97,8 +111,38 @@ class AbstractListener implements Listener {
* @param world the world
* @return true if region support is enabled
*/
protected boolean isRegionSupportEnabled(World world) {
protected static boolean isRegionSupportEnabled(World world) {
return getWorldConfig(world).useRegions;
}
protected RegionAssociable createRegionAssociable(Cause cause) {
Object rootCause = cause.getRootCause();
if (!cause.isKnown()) {
return Associables.constant(Association.NON_MEMBER);
} else if (rootCause instanceof Player) {
return getPlugin().wrapPlayer((Player) rootCause);
} else if (rootCause instanceof OfflinePlayer) {
return getPlugin().wrapOfflinePlayer((OfflinePlayer) rootCause);
} else if (rootCause instanceof Entity) {
RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery();
final Entity entity = (Entity) rootCause;
Location loc;
if (PaperLib.isPaper()
&& ((BukkitWorldConfiguration) getWorldConfig(BukkitAdapter.adapt(entity.getWorld()))).usePaperEntityOrigin) {
loc = entity.getOrigin();
if (loc == null) {
loc = entity.getLocation();
}
} else {
loc = entity.getLocation();
}
return new DelayedRegionOverlapAssociation(query, BukkitAdapter.adapt(loc));
} else if (rootCause instanceof Block) {
RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery();
return new DelayedRegionOverlapAssociation(query, BukkitAdapter.adapt(((Block) rootCause).getLocation()));
} else {
return Associables.constant(Association.NON_MEMBER);
}
}
}
@@ -22,21 +22,20 @@ package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration;
import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.entity.DamageEntityEvent;
import com.sk89q.worldguard.bukkit.event.inventory.UseItemEvent;
import com.sk89q.worldguard.bukkit.util.Entities;
import com.sk89q.worldguard.config.ConfigurationManager;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.entity.SpectralArrow;
import org.bukkit.entity.TippedArrow;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.Potion;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@@ -66,8 +65,8 @@ public class BlockedPotionsListener extends AbstractListener {
if (wcfg.blockPotions.contains(PotionEffectType.GLOWING)) {
blockedEffect = PotionEffectType.GLOWING;
}
} else if (originalEvent.getDamager() instanceof TippedArrow) {
TippedArrow tippedArrow = (TippedArrow) originalEvent.getDamager();
} else if (originalEvent.getDamager() instanceof Arrow) {
Arrow tippedArrow = (Arrow) originalEvent.getDamager();
PotionEffectType baseEffect = tippedArrow.getBasePotionData().getType().getEffectType();
if (wcfg.blockPotions.contains(baseEffect)) {
blockedEffect = baseEffect;
@@ -101,24 +100,12 @@ public class BlockedPotionsListener extends AbstractListener {
BukkitWorldConfiguration wcfg = (BukkitWorldConfiguration) cfg.get(BukkitAdapter.adapt(event.getWorld()));
ItemStack item = event.getItemStack();
// We only care about potions
boolean oldPotions = false;
try {
if (item.getType() != Material.POTION
&& item.getType() != Material.SPLASH_POTION
&& item.getType() != Material.LINGERING_POTION) {
return;
}
} catch (NoSuchFieldError ignored) {
// PotionMeta technically has been around since 1.7, so the code below
// *should* work still. we just have different materials now.
if (item.getType() != Material.POTION) {
return;
}
oldPotions = true;
if (item.getType() != Material.POTION
&& item.getType() != Material.SPLASH_POTION
&& item.getType() != Material.LINGERING_POTION) {
return;
}
if (!wcfg.blockPotions.isEmpty()) {
PotionEffectType blockedEffect = null;
@@ -149,13 +136,8 @@ public class BlockedPotionsListener extends AbstractListener {
if (player != null) {
if (getPlugin().hasPermission(player, "worldguard.override.potions")) {
boolean isSplash = false;
try {
isSplash = (!oldPotions && (item.getType() == Material.SPLASH_POTION || item.getType() == Material.LINGERING_POTION));
} catch (NoSuchFieldError ignored) {
}
isSplash |= (oldPotions && (Potion.fromItemStack(item).isSplash()));
if (isSplash && wcfg.blockPotionsAlways) {
if (wcfg.blockPotionsAlways && (item.getType() == Material.SPLASH_POTION
|| item.getType() == Material.LINGERING_POTION)) {
player.sendMessage(ChatColor.RED + "Sorry, potions with " +
blockedEffect.getName() + " can't be thrown, " +
"even if you have a permission to bypass it, " +
@@ -29,6 +29,7 @@ import com.sk89q.worldguard.bukkit.event.block.PlaceBlockEvent;
import com.sk89q.worldguard.bukkit.event.block.UseBlockEvent;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.SignChangeEvent;
@@ -135,7 +136,7 @@ public class ChestProtectionListener extends AbstractListener {
BukkitWorldConfiguration wcfg = (BukkitWorldConfiguration) getWorldConfig(WorldGuardPlugin.inst().wrapPlayer(player));
if (wcfg.signChestProtection) {
if (event.getLine(0).equalsIgnoreCase("[Lock]")) {
if ("[Lock]".equalsIgnoreCase(event.getLine(0))) {
if (wcfg.isChestProtectedPlacement(BukkitAdapter.adapt(event.getBlock().getLocation()), WorldGuardPlugin.inst().wrapPlayer(player))) {
player.sendMessage(ChatColor.DARK_RED + "You do not own the adjacent chest.");
event.getBlock().breakNaturally();
@@ -143,7 +144,7 @@ public class ChestProtectionListener extends AbstractListener {
return;
}
if (event.getBlock().getType() != Material.SIGN) {
if (!Tag.STANDING_SIGNS.isTagged(event.getBlock().getType())) {
player.sendMessage(ChatColor.RED
+ "The [Lock] sign must be a sign post, not a wall sign.");
@@ -152,7 +153,7 @@ public class ChestProtectionListener extends AbstractListener {
return;
}
if (!event.getLine(1).equalsIgnoreCase(player.getName())) {
if (!player.getName().equalsIgnoreCase(event.getLine(1))) {
player.sendMessage(ChatColor.RED
+ "The first owner line must be your name.");
@@ -164,7 +165,7 @@ public class ChestProtectionListener extends AbstractListener {
Material below = event.getBlock().getRelative(0, -1, 0).getType();
if (below == Material.TNT || below == Material.SAND
|| below == Material.GRAVEL || below == Material.SIGN) {
|| below == Material.GRAVEL || Tag.STANDING_SIGNS.isTagged(below)) {
player.sendMessage(ChatColor.RED
+ "That is not a safe block that you're putting this sign on.");
@@ -178,7 +179,7 @@ public class ChestProtectionListener extends AbstractListener {
+ "A chest or double chest above is now protected.");
}
} else if (!wcfg.disableSignChestProtectionCheck) {
if (event.getLine(0).equalsIgnoreCase("[Lock]")) {
if ("[Lock]".equalsIgnoreCase(event.getLine(0))) {
player.sendMessage(ChatColor.RED
+ "WorldGuard's sign chest protection is disabled.");
@@ -21,7 +21,6 @@ package com.sk89q.worldguard.bukkit.listener;
import static com.sk89q.worldguard.bukkit.cause.Cause.create;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration;
@@ -59,21 +58,24 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.Container;
import org.bukkit.block.DoubleChest;
import org.bukkit.block.Dropper;
import org.bukkit.block.Hopper;
import org.bukkit.block.PistonMoveReaction;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Dispenser;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Item;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Painting;
import org.bukkit.entity.Player;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Result;
@@ -85,6 +87,7 @@ import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.block.BlockExpEvent;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.block.BlockFertilizeEvent;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockMultiPlaceEvent;
@@ -126,6 +129,7 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerShearEntityEvent;
import org.bukkit.event.player.PlayerTakeLecternBookEvent;
import org.bukkit.event.player.PlayerUnleashEntityEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
@@ -136,10 +140,10 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.util.Vector;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import java.util.stream.Collectors;
public class EventAbstractionListener extends AbstractListener {
@@ -174,12 +178,14 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onBlockMultiPlace(BlockMultiPlaceEvent event) {
List<Block> blocks = new ArrayList<>();
for (BlockState bs : event.getReplacedBlockStates()) {
blocks.add(bs.getBlock());
List<Block> placed = event.getReplacedBlockStates().stream().map(BlockState::getBlock).collect(Collectors.toList());
int origAmt = placed.size();
PlaceBlockEvent delegateEvent = new PlaceBlockEvent(event, create(event.getPlayer()), event.getBlock().getWorld(),
placed, event.getBlockPlaced().getType());
Events.fireToCancel(event, delegateEvent);
if (origAmt != placed.size()) {
event.setCancelled(true);
}
Events.fireToCancel(event, new PlaceBlockEvent(event, create(event.getPlayer()),
event.getBlock().getWorld(), blocks, event.getBlock().getType()));
}
@EventHandler(ignoreCancelled = true)
@@ -188,7 +194,7 @@ public class EventAbstractionListener extends AbstractListener {
BlockState previousState = event.getBlockReplacedState();
// Some blocks, like tall grass and fire, get replaced
if (previousState.getType() != Material.AIR) {
if (previousState.getType() != Material.AIR && previousState.getType() != event.getBlockReplacedState().getType()) {
Events.fireToCancel(event, new BreakBlockEvent(event, create(event.getPlayer()), previousState.getLocation(), previousState.getType()));
}
@@ -240,39 +246,41 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onStructureGrowEvent(StructureGrowEvent event) {
int originalCount = event.getBlocks().size();
List<Block> blockList = Lists.transform(event.getBlocks(), new BlockStateAsBlockFunction());
Player player = event.getPlayer();
if (player != null) {
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(player), event.getLocation().getWorld(), blockList, Material.AIR));
} else {
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event, create(event.getLocation().getBlock()), event.getLocation().getWorld(), blockList, Material.AIR));
}
Events.fireBulkEventToCancel(event, new PlaceBlockEvent(event,
create(player == null ? event.getLocation().getBlock() : player),
event.getLocation().getWorld(), event.getBlocks()));
if (!event.isCancelled() && event.getBlocks().size() != originalCount) {
event.getLocation().getBlock().setType(Material.AIR);
}
}
// TODO: Handle EntityCreatePortalEvent?
@EventHandler(ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
Block block = event.getBlock();
Entity entity = event.getEntity();
Material to = event.getTo();
// Forget about Redstone ore, especially since we handle it in INTERACT
if (block.getType() == Material.REDSTONE_ORE && to == Material.REDSTONE_ORE) {
return;
}
Material toType = event.getTo();
Material fromType = block.getType();
Cause cause = create(entity);
// Fire two events: one as BREAK and one as PLACE
if (event.getTo() != Material.AIR && event.getBlock().getType() != Material.AIR) {
Events.fireToCancel(event, new BreakBlockEvent(event, create(entity), block));
Events.fireToCancel(event, new PlaceBlockEvent(event, create(entity), block.getLocation(), to));
if (toType != Material.AIR && fromType != Material.AIR) {
boolean trample = fromType == Material.FARMLAND && toType == Material.DIRT;
BreakBlockEvent breakDelagate = new BreakBlockEvent(event, cause, block);
if (trample) {
breakDelagate.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
}
if (!Events.fireToCancel(event, breakDelagate)) {
PlaceBlockEvent placeDelegate = new PlaceBlockEvent(event, cause, block.getLocation(), toType);
if (trample) {
placeDelegate.getRelevantFlags().add(Flags.TRAMPLE_BLOCKS);
}
Events.fireToCancel(event, placeDelegate);
}
} else {
if (event.getTo() == Material.AIR) {
if (toType == Material.AIR) {
// Track the source so later we can create a proper chain of causes
if (entity instanceof FallingBlock) {
Cause.trackParentCause(entity, block);
@@ -281,17 +289,18 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new SpawnEntityEvent(event, create(block), entity));
} else {
entityBreakBlockDebounce.debounce(
event.getBlock(), event.getEntity(), event, new BreakBlockEvent(event, create(entity), event.getBlock()));
block, event.getEntity(), event, new BreakBlockEvent(event, cause, block));
}
} else {
boolean wasCancelled = event.isCancelled();
Cause cause = create(entity);
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getLocation(), to));
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, block.getLocation(), toType));
if (event.isCancelled() && !wasCancelled && entity instanceof FallingBlock) {
FallingBlock fallingBlock = (FallingBlock) entity;
ItemStack itemStack = new ItemStack(fallingBlock.getBlockData().getMaterial(), 1);
final Material material = fallingBlock.getBlockData().getMaterial();
if (!material.isItem()) return;
ItemStack itemStack = new ItemStack(material, 1);
Item item = block.getWorld().dropItem(fallingBlock.getLocation(), itemStack);
item.setVelocity(new Vector());
if (Events.fireAndTestCancel(new SpawnEntityEvent(event, create(block, entity), item))) {
@@ -305,11 +314,6 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent event) {
Entity entity = event.getEntity();
if (event.getYield() == 0 && event.blockList().isEmpty()) {
// avoids ender dragon spam
return;
}
Events.fireBulkEventToCancel(event, new BreakBlockEvent(event, create(entity), event.getLocation().getWorld(), event.blockList(), Material.AIR));
}
@@ -353,7 +357,8 @@ public class EventAbstractionListener extends AbstractListener {
for (int i = 0; i < blocks.size(); i++) {
Block existing = blocks.get(i);
if (existing.getPistonMoveReaction() == PistonMoveReaction.MOVE
|| existing.getPistonMoveReaction() == PistonMoveReaction.PUSH_ONLY) {
|| existing.getPistonMoveReaction() == PistonMoveReaction.PUSH_ONLY
|| existing.getType() == Material.PISTON || existing.getType() == Material.STICKY_PISTON) {
blocks.set(i, existing.getRelative(dir));
}
}
@@ -425,8 +430,8 @@ public class EventAbstractionListener extends AbstractListener {
// Only fire events for blocks that are modified when right clicked
final boolean hasItemInteraction = item != null && isItemAppliedToBlock(item, clicked)
&& event.getAction() == Action.RIGHT_CLICK_BLOCK;
modifiesWorld = isBlockModifiedOnClick(clicked, event.getAction() == Action.RIGHT_CLICK_BLOCK)
|| hasItemInteraction;
modifiesWorld = hasItemInteraction
|| isBlockModifiedOnClick(clicked, event.getAction() == Action.RIGHT_CLICK_BLOCK);
if (Events.fireAndTestCancel(new UseBlockEvent(event, cause, clicked).setAllowed(!modifiesWorld))) {
event.setUseInteractedBlock(Result.DENY);
@@ -443,6 +448,7 @@ public class EventAbstractionListener extends AbstractListener {
if (hasItemInteraction) {
if (Events.fireAndTestCancel(new PlaceBlockEvent(event, cause, clicked.getLocation(), clicked.getType()))) {
event.setUseItemInHand(Result.DENY);
event.setUseInteractedBlock(Result.DENY);
}
}
@@ -495,6 +501,12 @@ public class EventAbstractionListener extends AbstractListener {
event.getBlock()).setAllowed(hasInteractBypass(event.getBlock())));
}
@EventHandler(ignoreCancelled = true)
public void onBlockFertilize(BlockFertilizeEvent event) {
Cause cause = create(event.getPlayer(), event.getBlock());
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, event.getBlock().getWorld(), event.getBlocks()));
}
@EventHandler(ignoreCancelled = true)
public void onBlockIgnite(BlockIgniteEvent event) {
Block block = event.getBlock();
@@ -599,7 +611,7 @@ public class EventAbstractionListener extends AbstractListener {
Material toType = to.getType();
// Liquids pass this event when flowing to solid blocks
if (toType.isSolid() && Materials.isLiquid(fromType)) {
if (Materials.isLiquid(fromType) && toType.isSolid()) {
return;
}
@@ -635,27 +647,7 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new SpawnEntityEvent(event, Cause.unknown(), event.getEntity()));
}
break;
case NATURAL:
case JOCKEY:
case CHUNK_GEN:
case SPAWNER:
case LIGHTNING:
case BUILD_SNOWMAN:
case BUILD_IRONGOLEM:
case BUILD_WITHER:
case VILLAGE_DEFENSE:
case VILLAGE_INVASION:
case BREEDING:
case SLIME_SPLIT:
case REINFORCEMENTS:
case NETHER_PORTAL:
case INFECTION:
case CURED:
case OCELOT_BABY:
case SILVERFISH_BLOCK:
case MOUNT:
case CUSTOM:
case DEFAULT:
default:
}
}
@@ -678,6 +670,15 @@ public class EventAbstractionListener extends AbstractListener {
if (event.isCancelled() && remover instanceof Player) {
playDenyEffect((Player) remover, event.getEntity().getLocation());
}
} else if (event.getCause() == HangingBreakEvent.RemoveCause.EXPLOSION){
DestroyEntityEvent destroyEntityEvent = new DestroyEntityEvent(event, Cause.unknown(), event.getEntity());
destroyEntityEvent.getRelevantFlags().add(Flags.OTHER_EXPLOSION);
if (event.getEntity() instanceof ItemFrame) {
destroyEntityEvent.getRelevantFlags().add(Flags.ENTITY_ITEM_FRAME_DESTROY);
} else if (event.getEntity() instanceof Painting) {
destroyEntityEvent.getRelevantFlags().add(Flags.ENTITY_PAINTING_DESTROY);
}
Events.fireToCancel(event, destroyEntityEvent);
}
}
@@ -756,8 +757,20 @@ public class EventAbstractionListener extends AbstractListener {
? player.getInventory().getItemInOffHand() : player.getInventory().getItemInMainHand();
Entity entity = event.getRightClicked();
Events.fireToCancel(event, new UseItemEvent(event, create(player), world, item));
Events.fireToCancel(event, new UseEntityEvent(event, create(player), entity));
if (Events.fireToCancel(event, new UseItemEvent(event, create(player), world, item))) {
return;
}
final UseEntityEvent useEntityEvent = new UseEntityEvent(event, create(player), entity);
Material matchingItem = Materials.getRelatedMaterial(entity.getType());
if (matchingItem != null && hasInteractBypass(world, matchingItem)) {
useEntityEvent.setAllowed(true);
}
if (!Events.fireToCancel(event, useEntityEvent)) {
// so this is a hack but CreeperIgniteEvent doesn't actually tell us who, so we need to do it here
if (item.getType() == Material.FLINT_AND_STEEL && entity.getType() == EntityType.CREEPER) {
Cause.trackParentCause(entity, player);
}
}
}
@EventHandler(ignoreCancelled = true)
@@ -774,7 +787,13 @@ public class EventAbstractionListener extends AbstractListener {
} else if (event instanceof EntityDamageByEntityEvent) {
EntityDamageByEntityEvent entityEvent = (EntityDamageByEntityEvent) event;
Entity damager = entityEvent.getDamager();
Events.fireToCancel(event, new DamageEntityEvent(event, create(damager), event.getEntity()));
final DamageEntityEvent eventToFire = new DamageEntityEvent(event, create(damager), event.getEntity());
if (damager instanceof Firework) {
eventToFire.getRelevantFlags().add(Flags.FIREWORK_DAMAGE);
} else if (damager instanceof Creeper) {
eventToFire.getRelevantFlags().add(Flags.CREEPER_EXPLOSION);
}
Events.fireToCancel(event, eventToFire);
// Item use event with the item in hand
// Older blacklist handler code used this, although it suffers from
@@ -806,7 +825,7 @@ public class EventAbstractionListener extends AbstractListener {
if (event instanceof PlayerUnleashEntityEvent) {
PlayerUnleashEntityEvent playerEvent = (PlayerUnleashEntityEvent) event;
Events.fireToCancel(playerEvent, new UseEntityEvent(playerEvent, create(playerEvent.getPlayer()), event.getEntity()));
} // TODO: Raise anyway?
}
}
@EventHandler(ignoreCancelled = true)
@@ -848,30 +867,28 @@ public class EventAbstractionListener extends AbstractListener {
@EventHandler(ignoreCancelled = true)
public void onInventoryOpen(InventoryOpenEvent event) {
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState) {
Events.fireToCancel(event, new UseBlockEvent(event, create(event.getPlayer()), ((BlockState) holder).getBlock()));
} else if (holder instanceof Entity) {
if (!(holder instanceof Player)) {
Events.fireToCancel(event, new UseEntityEvent(event, create(event.getPlayer()), (Entity) holder));
}
}
if (holder instanceof Entity && holder == event.getPlayer()) return;
handleInventoryHolderUse(event, create(event.getPlayer()), holder);
}
@EventHandler(ignoreCancelled = true)
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
final InventoryHolder causeHolder = event.getInitiator().getHolder();
InventoryHolder sourceHolder = event.getSource().getHolder();
InventoryHolder targetHolder = event.getDestination().getHolder();
if ((causeHolder instanceof Hopper || causeHolder instanceof Dropper)
&& ((BukkitWorldConfiguration) WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(
BukkitAdapter.adapt(((Container) causeHolder).getWorld()))).ignoreHopperMoveEvents) {
if (causeHolder instanceof Hopper
&& getWorldConfig(BukkitAdapter.adapt((((Hopper) causeHolder).getWorld()))).ignoreHopperMoveEvents) {
return;
} else if (causeHolder instanceof HopperMinecart
&& getWorldConfig(BukkitAdapter.adapt((((HopperMinecart) causeHolder).getWorld()))).ignoreHopperMoveEvents) {
return;
}
Entry entry;
if ((entry = moveItemDebounce.tryDebounce(event)) != null) {
InventoryHolder sourceHolder = event.getSource().getHolder();
InventoryHolder targetHolder = event.getDestination().getHolder();
Cause cause;
if (causeHolder instanceof Entity) {
@@ -990,6 +1007,13 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireBulkEventToCancel(event, eventToFire);
}
@EventHandler(ignoreCancelled = true)
public void onTakeLecternBook(PlayerTakeLecternBookEvent event) {
final UseBlockEvent useEvent = new UseBlockEvent(event, create(event.getPlayer()), event.getLectern().getBlock());
useEvent.getRelevantFlags().add(Flags.CHEST_ACCESS);
Events.fireToCancel(event, useEvent);
}
/**
* Handle the right click of a block while an item is held.
*
@@ -1017,7 +1041,7 @@ public class EventAbstractionListener extends AbstractListener {
if (entityType == null) {
entityType = EntityType.MINECART;
}
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), entityType));
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, clicked.getLocation().add(0.5, 0, 0.5), entityType));
return;
}
@@ -1044,6 +1068,13 @@ public class EventAbstractionListener extends AbstractListener {
Events.fireToCancel(event, new SpawnEntityEvent(event, cause, placed.getLocation().add(0.5, 0, 0.5), Materials.getEntitySpawnEgg(item.getType())));
return;
}
// handle water/lava placement
if (item != null && (item.getType() == Material.WATER_BUCKET || item.getType() == Material.LAVA_BUCKET)) {
Events.fireToCancel(event, new PlaceBlockEvent(event, cause, placed.getLocation(),
item.getType() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA));
return;
}
}
private static <T extends Event & Cancellable> void handleInventoryHolderUse(T originalEvent, Cause cause, InventoryHolder holder) {
@@ -1052,47 +1083,64 @@ public class EventAbstractionListener extends AbstractListener {
}
if (holder instanceof Entity) {
Events.fireToCancel(originalEvent, new UseEntityEvent(originalEvent, cause, (Entity) holder));
} else if (holder instanceof BlockState) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((BlockState) holder).getBlock()));
} else if (holder instanceof DoubleChest) {
InventoryHolder left = ((DoubleChest) holder).getLeftSide();
InventoryHolder right = ((DoubleChest) holder).getRightSide();
if (left instanceof Chest) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((Chest) left).getBlock()));
Entity entity = (Entity) holder;
Material mat = Materials.getRelatedMaterial((entity).getType());
UseEntityEvent useEntityEvent = new UseEntityEvent(originalEvent, cause, entity);
if (mat != null && hasInteractBypass((entity).getWorld(), mat)) {
useEntityEvent.setAllowed(true);
}
if (right instanceof Chest) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((Chest) right).getBlock()));
Events.fireToCancel(originalEvent, useEntityEvent);
} else {
if (holder instanceof BlockState) {
final BlockState block = (BlockState) holder;
final UseBlockEvent useBlockEvent = new UseBlockEvent(originalEvent, cause, block.getBlock());
if (hasInteractBypass(block.getWorld(), block.getType())) {
useBlockEvent.setAllowed(true);
}
Events.fireToCancel(originalEvent, useBlockEvent);
} else if (holder instanceof DoubleChest) {
InventoryHolder left = ((DoubleChest) holder).getLeftSide();
InventoryHolder right = ((DoubleChest) holder).getRightSide();
if (left instanceof Chest) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((Chest) left).getBlock()));
}
if (right instanceof Chest) {
Events.fireToCancel(originalEvent, new UseBlockEvent(originalEvent, cause, ((Chest) right).getBlock()));
}
}
}
}
private boolean hasInteractBypass(Block block) {
private static boolean hasInteractBypass(Block block) {
return ((BukkitWorldConfiguration) getWorldConfig(BukkitAdapter.adapt(block.getWorld()))).allowAllInteract.test(block);
}
private boolean hasInteractBypass(World world, ItemStack item) {
private static boolean hasInteractBypass(World world, Material material) {
return ((BukkitWorldConfiguration) getWorldConfig(BukkitAdapter.adapt(world))).allowAllInteract.test(material);
}
private static boolean hasInteractBypass(World world, ItemStack item) {
return ((BukkitWorldConfiguration) getWorldConfig(BukkitAdapter.adapt(world))).allowAllInteract.test(item);
}
private boolean isBlockModifiedOnClick(Block block, boolean rightClick) {
private static boolean isBlockModifiedOnClick(Block block, boolean rightClick) {
return Materials.isBlockModifiedOnClick(block.getType(), rightClick) && !hasInteractBypass(block);
}
private boolean isItemAppliedToBlock(ItemStack item, Block clicked) {
private static boolean isItemAppliedToBlock(ItemStack item, Block clicked) {
return Materials.isItemAppliedToBlock(item.getType(), clicked.getType())
&& !hasInteractBypass(clicked)
&& !hasInteractBypass(clicked.getWorld(), item);
}
private void playDenyEffect(Player player, Location location) {
private static void playDenyEffect(Player player, Location location) {
//player.playSound(location, Sound.SUCCESSFUL_HIT, 0.2f, 0.4f);
if (WorldGuard.getInstance().getPlatform().getGlobalStateManager().particleEffects) {
player.playEffect(location, Effect.SMOKE, BlockFace.UP);
}
}
private void playDenyEffect(Location location) {
private static void playDenyEffect(Location location) {
if (WorldGuard.getInstance().getPlatform().getGlobalStateManager().particleEffects) {
location.getWorld().playEffect(location, Effect.SMOKE, BlockFace.UP);
}
@@ -39,7 +39,6 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
@@ -109,6 +108,10 @@ public class RegionFlagsListener extends AbstractListener {
if (event.getCause().find(EntityType.ENDERMAN) != null) {
event.filter(testState(query, Flags.ENDER_BUILD), false);
}
if (event.getCause().find(EntityType.RAVAGER) != null) {
event.filter(testState(query, Flags.RAVAGER_RAVAGE), false);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
@@ -126,27 +129,15 @@ public class RegionFlagsListener extends AbstractListener {
return;
}
} else {
try {
if (entity instanceof Player && event.getCause() == DamageCause.FLY_INTO_WALL) {
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer((Player) entity);
if (!query.testState(BukkitAdapter.adapt(entity.getLocation()), localPlayer, Flags.FALL_DAMAGE)) {
event.setCancelled(true);
return;
}
}
} catch (NoSuchFieldError ignored) {
}
}
if (event instanceof EntityDamageByEntityEvent) {
Entity damager = (((EntityDamageByEntityEvent) event)).getDamager();
if (damager != null && damager.getType() == EntityType.FIREWORK) {
if (!query.testState(BukkitAdapter.adapt(entity.getLocation()), (RegionAssociable) null, Flags.FIREWORK_DAMAGE)) {
if (entity instanceof Player && event.getCause() == DamageCause.FLY_INTO_WALL) {
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer((Player) entity);
if (!query.testState(BukkitAdapter.adapt(entity.getLocation()), localPlayer, Flags.FALL_DAMAGE)) {
event.setCancelled(true);
return;
}
}
}
}
/**
@@ -41,10 +41,7 @@ import com.sk89q.worldguard.bukkit.util.InteropUtils;
import com.sk89q.worldguard.bukkit.util.Materials;
import com.sk89q.worldguard.commands.CommandUtils;
import com.sk89q.worldguard.config.WorldConfiguration;
import com.sk89q.worldguard.domains.Association;
import com.sk89q.worldguard.internal.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.DelayedRegionOverlapAssociation;
import com.sk89q.worldguard.protection.association.Associables;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
@@ -53,7 +50,6 @@ import com.sk89q.worldguard.protection.regions.RegionQuery;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
@@ -140,38 +136,19 @@ public class RegionProtectionListener extends AbstractListener {
if (rootCause instanceof Player) {
Player player = (Player) rootCause;
LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
WorldConfiguration config = getWorldConfig(BukkitAdapter.adapt(world));
com.sk89q.worldedit.world.World localWorld = BukkitAdapter.adapt(world);
WorldConfiguration config = getWorldConfig(localWorld);
if (config.fakePlayerBuildOverride && InteropUtils.isFakePlayer(player)) {
return true;
}
return !pvp && new RegionPermissionModel(localPlayer).mayIgnoreRegionProtection(BukkitAdapter.adapt(world));
return !pvp && WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(localPlayer, localWorld);
} else {
return false;
}
}
private RegionAssociable createRegionAssociable(Cause cause) {
Object rootCause = cause.getRootCause();
if (!cause.isKnown()) {
return Associables.constant(Association.NON_MEMBER);
} else if (rootCause instanceof Player) {
return getPlugin().wrapPlayer((Player) rootCause);
} else if (rootCause instanceof OfflinePlayer) {
return getPlugin().wrapOfflinePlayer((OfflinePlayer) rootCause);
} else if (rootCause instanceof Entity) {
RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery();
return new DelayedRegionOverlapAssociation(query, BukkitAdapter.adapt(((Entity) rootCause).getLocation()));
} else if (rootCause instanceof Block) {
RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery();
return new DelayedRegionOverlapAssociation(query, BukkitAdapter.adapt(((Block) rootCause).getLocation()));
} else {
return Associables.constant(Association.NON_MEMBER);
}
}
@EventHandler(ignoreCancelled = true)
public void onPlaceBlock(final PlaceBlockEvent event) {
if (event.getResult() == Result.ALLOW) return; // Don't care about events that have been pre-allowed
@@ -416,15 +393,16 @@ public class RegionProtectionListener extends AbstractListener {
String what;
/* Hostile / ambient mob override */
final EntityType type = event.getEntity().getType();
if (Entities.isHostile(event.getEntity()) || Entities.isAmbient(event.getEntity())
|| Entities.isNPC(event.getEntity())) {
final Entity entity = event.getEntity();
final EntityType type = entity.getType();
if (Entities.isHostile(entity) || Entities.isAmbient(entity)
|| Entities.isNPC(entity) || entity instanceof Player) {
canUse = event.getRelevantFlags().isEmpty() || query.queryState(BukkitAdapter.adapt(target), associable, combine(event)) != State.DENY;
what = "use that";
/* Paintings, item frames, etc. */
} else if (Entities.isConsideredBuildingIfUsed(event.getEntity())) {
} else if (Entities.isConsideredBuildingIfUsed(entity)) {
if (type == EntityType.ITEM_FRAME && event.getCause().getFirstPlayer() != null
&& ((ItemFrame) event.getEntity()).getItem().getType() != Material.AIR) {
&& ((ItemFrame) entity).getItem().getType() != Material.AIR) {
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.ITEM_FRAME_ROTATE));
what = "change that";
} else if (Entities.isMinecart(type)) {
@@ -435,7 +413,7 @@ public class RegionProtectionListener extends AbstractListener {
what = "change that";
}
/* Ridden on use */
} else if (Entities.isRiddenOnUse(event.getEntity())) {
} else if (Entities.isRiddenOnUse(entity)) {
canUse = query.testBuild(BukkitAdapter.adapt(target), associable, combine(event, Flags.RIDE, Flags.INTERACT));
what = "ride that";
@@ -620,7 +620,7 @@ public class WorldGuardBlockListener implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBlockGrow(BlockGrowEvent event) {
WorldConfiguration wcfg = getWorldConfig(event.getBlock().getWorld());
final Material type = event.getBlock().getType();
final Material type = event.getNewState().getType();
if (Materials.isCrop(type)) {
if (wcfg.disableCropGrowth) {
@@ -20,6 +20,7 @@
package com.sk89q.worldguard.bukkit.listener;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitWorldConfiguration;
@@ -31,11 +32,14 @@ import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.RegionQuery;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.EnderCrystal;
@@ -62,7 +66,6 @@ import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.event.entity.CreeperPowerEvent;
import org.bukkit.event.entity.EntityBreakDoorEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityCreatePortalEvent;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
@@ -75,6 +78,7 @@ import org.bukkit.event.entity.EntityTransformEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.event.entity.PigZapEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.world.PortalCreateEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.ProjectileSource;
@@ -103,9 +107,6 @@ public class WorldGuardEntityListener implements Listener {
*/
public void registerEvents() {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
if (!EntityCreatePortalEvent.class.isAnnotationPresent(Deprecated.class)) {
plugin.getServer().getPluginManager().registerEvents(new UselessIn114Listener(), plugin);
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
@@ -163,6 +164,9 @@ public class WorldGuardEntityListener implements Listener {
if (wcfg.teleportOnVoid && type == DamageCause.VOID) {
localPlayer.findFreePosition();
if (wcfg.safeFallOnVoid) {
localPlayer.resetFallDistance();
}
event.setCancelled(true);
return;
}
@@ -278,13 +282,6 @@ public class WorldGuardEntityListener implements Listener {
event.setCancelled(true);
return;
}
if (attacker instanceof Creeper) {
if (!set.testState(localPlayer, Flags.CREEPER_EXPLOSION) && wcfg.explosionFlagCancellation) {
event.setCancelled(true);
return;
}
}
}
}
}
@@ -670,17 +667,48 @@ public class WorldGuardEntityListener implements Listener {
}
}
private static class UselessIn114Listener implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onCreatePortal(EntityCreatePortalEvent event) {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(event.getEntity().getWorld()));
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onCreatePortal(PortalCreateEvent event) {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
final com.sk89q.worldedit.world.World world = BukkitAdapter.adapt(event.getWorld());
WorldConfiguration wcfg = cfg.get(world);
switch (event.getEntityType()) {
case ENDER_DRAGON:
if (wcfg.blockEnderDragonPortalCreation) event.setCancelled(true);
break;
if (wcfg.regionNetherPortalProtection
&& event.getReason() == PortalCreateEvent.CreateReason.NETHER_PAIR
&& !event.getBlocks().isEmpty()) {
final RegionManager regionManager = WorldGuard.getInstance().getPlatform().getRegionContainer()
.get(world);
if (regionManager == null) return;
LocalPlayer associable = null;
if (event.getEntity() instanceof Player) {
associable = plugin.wrapPlayer(((Player) event.getEntity()));
if (WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(associable, world)) {
return;
}
}
BlockVector3 min = null;
BlockVector3 max = null;
for (BlockState block : event.getBlocks()) {
BlockVector3 loc = BlockVector3.at(block.getX(), block.getY(), block.getZ());
min = min == null ? loc : loc.getMinimum(min);
max = max == null ? loc : loc.getMaximum(max);
}
ProtectedCuboidRegion target = new ProtectedCuboidRegion("__portal_check", true, min, max);
final ApplicableRegionSet regions = regionManager.getApplicableRegions(target);
if (!regions.testState(associable, Flags.BUILD, Flags.BLOCK_PLACE)) {
if (associable != null) {
// NB there is no way to cancel the teleport without PTA (since PlayerPortal doesn't have block info)
// removing PTA was a mistake
associable.print("Destination is an a protected area.");
}
event.setCancelled(true);
}
}
// NOTE: as of right now, bukkit doesn't fire this event for this (despite deprecating EntityCreatePortalEvent for it)
// maybe one day this code will be useful
if (event.getEntity() instanceof EnderDragon && wcfg.blockEnderDragonPortalCreation) {
event.setCancelled(true);
}
}
@@ -31,8 +31,6 @@ import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.config.WorldConfiguration;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionQuery;
import com.sk89q.worldguard.session.MoveType;
@@ -41,9 +39,7 @@ import com.sk89q.worldguard.session.handler.GameModeFlag;
import com.sk89q.worldguard.util.Entities;
import com.sk89q.worldguard.util.command.CommandFilter;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TravelAgent;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
@@ -60,20 +56,18 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.PluginManager;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
/**
* Handles all events thrown in relation to a player.
*/
@@ -143,7 +137,7 @@ public class WorldGuardPlayerListener implements Listener {
if (removed > 10) {
log.info("Halt-Act: " + removed + " entities (>10) auto-removed from "
+ player.getWorld().toString());
+ player.getWorld());
}
}
@@ -181,7 +175,7 @@ public class WorldGuardPlayerListener implements Listener {
anyRemoved = true;
}
}
if (anyRemoved && event.getRecipients().size() == 0 && wcfg.regionCancelEmptyChatEvents) {
if (anyRemoved && event.getRecipients().isEmpty() && wcfg.regionCancelEmptyChatEvents) {
event.setCancelled(true);
}
}
@@ -368,7 +362,6 @@ public class WorldGuardPlayerListener implements Listener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerTeleport(PlayerTeleportEvent event) {
World world = event.getFrom().getWorld();
Player player = event.getPlayer();
LocalPlayer localPlayer = plugin.wrapPlayer(player);
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
@@ -386,89 +379,41 @@ public class WorldGuardPlayerListener implements Listener {
String message = null;
if (!setFrom.testState(localPlayer, Flags.ENDERPEARL)) {
cancel = true;
message = set.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE);
message = setFrom.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE);
} else if (!set.testState(localPlayer, Flags.ENDERPEARL)) {
cancel = true;
message = set.queryValue(localPlayer, Flags.ENTRY_DENY_MESSAGE);
}
if (cancel) {
player.sendMessage(message);
if (message != null) {
player.sendMessage(message);
}
event.setCancelled(true);
return;
}
}
}
if (event.getCause() == TeleportCause.CHORUS_FRUIT) {
} else if (event.getCause() == TeleportCause.CHORUS_FRUIT) {
if (!WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(localPlayer, localPlayer.getWorld())) {
boolean cancel = false;
String message = null;
if (!setFrom.testState(localPlayer, Flags.CHORUS_TELEPORT)) {
cancel = true;
message = set.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE);
message = setFrom.queryValue(localPlayer, Flags.EXIT_DENY_MESSAGE);
} else if (!set.testState(localPlayer, Flags.CHORUS_TELEPORT)) {
cancel = true;
message = set.queryValue(localPlayer, Flags.ENTRY_DENY_MESSAGE);
}
if (cancel) {
player.sendMessage(message);
if (message != null) {
player.sendMessage(message);
}
event.setCancelled(true);
return;
}
}
}
if (null != WorldGuard.getInstance().getPlatform().getSessionManager().get(localPlayer).testMoveTo(localPlayer,
BukkitAdapter.adapt(event.getTo()),
MoveType.TELEPORT)) {
event.setCancelled(true);
return;
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void onPlayerPortal(PlayerPortalEvent event) {
if (event.getTo() == null) { // apparently this counts as a cancelled event, implementation specific though
return;
}
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
LocalPlayer localPlayer = plugin.wrapPlayer(event.getPlayer());
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(event.getTo().getWorld()));
if (!wcfg.regionNetherPortalProtection) return;
if (event.getCause() != TeleportCause.NETHER_PORTAL) {
return;
}
try {
if (!event.useTravelAgent()) { // either end travel (even though we checked cause) or another plugin is fucking with us, shouldn't create a portal though
return;
}
} catch (NoSuchMethodError ignored) {
return;
}
TravelAgent pta = event.getPortalTravelAgent();
if (pta == null) { // possible, but shouldn't create a portal
return;
}
if (pta.findPortal(event.getTo()) != null) {
return; // portal exists...it shouldn't make a new one
}
// HOPEFULLY covered everything the server can throw at us...proceed protection checking
// a lot of that is implementation specific though
// hackily estimate the area that could be effected by this event, since the server refuses to tell us
int radius = pta.getCreationRadius();
Location min = event.getTo().clone().subtract(radius, radius, radius);
Location max = event.getTo().clone().add(radius, radius, radius);
com.sk89q.worldedit.world.World world = BukkitAdapter.adapt(event.getTo().getWorld());
ProtectedRegion check = new ProtectedCuboidRegion("__portalcheck__", BukkitAdapter.adapt(min.getBlock().getLocation()).toVector().toBlockPoint(),
BukkitAdapter.adapt(max.getBlock().getLocation()).toVector().toBlockPoint());
if (wcfg.useRegions && !WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(localPlayer, world)) {
RegionManager mgr = WorldGuard.getInstance().getPlatform().getRegionContainer().get(world);
if (mgr == null) return;
ApplicableRegionSet set = mgr.getApplicableRegions(check);
if (!set.testState(plugin.wrapPlayer(event.getPlayer()), Flags.BUILD)) {
event.getPlayer().sendMessage(ChatColor.RED + "Destination is in a protected area.");
if (null != WorldGuard.getInstance().getPlatform().getSessionManager().get(localPlayer)
.testMoveTo(localPlayer, BukkitAdapter.adapt(event.getTo()), MoveType.TELEPORT)) {
event.setCancelled(true);
return;
}
@@ -29,6 +29,8 @@ import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -93,8 +95,12 @@ public class WorldGuardWeatherListener implements Listener {
ConfigurationManager cfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager();
WorldConfiguration wcfg = cfg.get(BukkitAdapter.adapt(event.getWorld()));
if (wcfg.disallowedLightningBlocks.size() > 0) {
Material targetId = event.getLightning().getLocation().getBlock().getType();
if (!wcfg.disallowedLightningBlocks.isEmpty()) {
final Block target = event.getLightning().getLocation().getBlock();
Material targetId = target.getType();
if (targetId == Material.AIR) {
targetId = target.getRelative(BlockFace.DOWN).getType();
}
if (wcfg.disallowedLightningBlocks.contains(BukkitAdapter.asBlockType(targetId).getId())) {
event.setCancelled(true);
}
@@ -24,13 +24,14 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.bukkit.BukkitPlayer;
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
import com.sk89q.worldguard.session.AbstractSessionManager;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.util.profile.Profile;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import java.util.Collection;
@@ -57,10 +58,12 @@ public class BukkitSessionManager extends AbstractSessionManager implements Runn
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
public void onPlayerProcess(ProcessPlayerEvent event) {
// Pre-load a session
LocalPlayer player = WorldGuardPlugin.inst().wrapPlayer(event.getPlayer());
get(player).initialize(player);
WorldGuard.getInstance().getExecutorService().submit(() ->
WorldGuard.getInstance().getProfileCache().put(new Profile(player.getUniqueId(), player.getName())));
}
@Override
@@ -75,7 +78,7 @@ public class BukkitSessionManager extends AbstractSessionManager implements Runn
public boolean hasBypass(LocalPlayer player, World world) {
if (player instanceof BukkitPlayer) {
if (((BukkitPlayer) player).getPlayer().hasMetadata("NPC")
&& WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).fakePlayerBuildOverride)
&& WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).fakePlayerBuildOverride)
return true;
}
return super.hasBypass(player, world);
@@ -19,6 +19,7 @@
package com.sk89q.worldguard.bukkit.util;
import io.papermc.lib.PaperLib;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
@@ -45,7 +46,7 @@ public final class Blocks {
* @return a list of connected blocks, not including the given block
*/
public static List<Block> getConnected(Block block) {
BlockState state = block.getState();
BlockState state = PaperLib.getBlockState(block, false).getState();
BlockData data = state.getBlockData();
if (data instanceof Bed) {
@@ -21,6 +21,7 @@ package com.sk89q.worldguard.bukkit.util;
import org.bukkit.entity.Ambient;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Creature;
import org.bukkit.entity.EnderCrystal;
import org.bukkit.entity.EnderDragon;
@@ -40,7 +41,6 @@ import org.bukkit.entity.Slime;
import org.bukkit.entity.SpectralArrow;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.TippedArrow;
import org.bukkit.entity.Vehicle;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.inventory.InventoryHolder;
@@ -212,7 +212,7 @@ public final class Entities {
}
public static boolean isPotionArrow(Entity entity) {
return entity instanceof TippedArrow || entity instanceof SpectralArrow;
return entity instanceof Arrow || entity instanceof SpectralArrow;
}
public static boolean isAoECloud(EntityType type) {
@@ -52,7 +52,6 @@ public final class Materials {
private static final Map<Material, Integer> MATERIAL_FLAGS = new EnumMap<>(Material.class);
private static final Set<PotionEffectType> DAMAGE_EFFECTS = new HashSet<>();
private static Set<Material> shulkerBoxes = new HashSet<>();
static {
@@ -93,6 +92,7 @@ public final class Materials {
ENTITY_ITEMS.put(EntityType.SPLASH_POTION, Material.POTION);
ENTITY_ITEMS.put(EntityType.EGG, Material.EGG);
ENTITY_ITEMS.put(EntityType.ARMOR_STAND, Material.ARMOR_STAND);
ENTITY_ITEMS.put(EntityType.ENDER_CRYSTAL, Material.END_CRYSTAL);
MATERIAL_FLAGS.put(Material.AIR, 0);
MATERIAL_FLAGS.put(Material.STONE, 0);
@@ -123,20 +123,10 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.PISTON, 0);
MATERIAL_FLAGS.put(Material.PISTON_HEAD, 0);
MATERIAL_FLAGS.put(Material.MOVING_PISTON, 0);
MATERIAL_FLAGS.put(Material.DANDELION, 0);
MATERIAL_FLAGS.put(Material.BLUE_ORCHID, 0);
MATERIAL_FLAGS.put(Material.ALLIUM, 0);
MATERIAL_FLAGS.put(Material.AZURE_BLUET, 0);
MATERIAL_FLAGS.put(Material.ORANGE_TULIP, 0);
MATERIAL_FLAGS.put(Material.PINK_TULIP, 0);
MATERIAL_FLAGS.put(Material.RED_TULIP, 0);
MATERIAL_FLAGS.put(Material.WHITE_TULIP, 0);
MATERIAL_FLAGS.put(Material.OXEYE_DAISY, 0);
MATERIAL_FLAGS.put(Material.SUNFLOWER, 0);
MATERIAL_FLAGS.put(Material.LILAC, 0);
MATERIAL_FLAGS.put(Material.PEONY, 0);
MATERIAL_FLAGS.put(Material.ROSE_BUSH, 0);
MATERIAL_FLAGS.put(Material.POPPY, 0);
MATERIAL_FLAGS.put(Material.BROWN_MUSHROOM, 0);
MATERIAL_FLAGS.put(Material.RED_MUSHROOM, 0);
MATERIAL_FLAGS.put(Material.GOLD_BLOCK, 0);
@@ -234,7 +224,6 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.EMERALD_BLOCK, 0);
MATERIAL_FLAGS.put(Material.COMMAND_BLOCK, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BEACON, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.COBBLESTONE_WALL, 0);
MATERIAL_FLAGS.put(Material.ANVIL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.CHIPPED_ANVIL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.DAMAGED_ANVIL, MODIFIED_ON_RIGHT);
@@ -405,7 +394,6 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.MAGENTA_STAINED_GLASS, 0);
MATERIAL_FLAGS.put(Material.MAGENTA_STAINED_GLASS_PANE, 0);
MATERIAL_FLAGS.put(Material.MAGENTA_TERRACOTTA, 0);
MATERIAL_FLAGS.put(Material.MOSSY_COBBLESTONE_WALL, 0);
MATERIAL_FLAGS.put(Material.MUSHROOM_STEM, 0);
MATERIAL_FLAGS.put(Material.OBSERVER, 0);
MATERIAL_FLAGS.put(Material.ORANGE_STAINED_GLASS, 0);
@@ -446,6 +434,26 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.YELLOW_STAINED_GLASS_PANE, 0);
MATERIAL_FLAGS.put(Material.YELLOW_TERRACOTTA, 0);
MATERIAL_FLAGS.put(Material.BAMBOO, 0);
MATERIAL_FLAGS.put(Material.BAMBOO_SAPLING, 0);
MATERIAL_FLAGS.put(Material.BARREL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BELL, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BLAST_FURNACE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.CAMPFIRE, MODIFIED_ON_RIGHT | MODIFIED_ON_LEFT);
MATERIAL_FLAGS.put(Material.CARTOGRAPHY_TABLE, 0);
MATERIAL_FLAGS.put(Material.COMPOSTER, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.FLETCHING_TABLE, 0);
MATERIAL_FLAGS.put(Material.GRINDSTONE, 0);
MATERIAL_FLAGS.put(Material.JIGSAW, MODIFIED_ON_RIGHT | MODIFIED_ON_LEFT);
MATERIAL_FLAGS.put(Material.LANTERN, 0);
MATERIAL_FLAGS.put(Material.LECTERN, 0);
MATERIAL_FLAGS.put(Material.LOOM, 0);
MATERIAL_FLAGS.put(Material.SCAFFOLDING, 0);
MATERIAL_FLAGS.put(Material.SMITHING_TABLE, 0);
MATERIAL_FLAGS.put(Material.SMOKER, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.STONECUTTER, 0);
MATERIAL_FLAGS.put(Material.SWEET_BERRY_BUSH, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.IRON_SHOVEL, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.IRON_PICKAXE, 0);
MATERIAL_FLAGS.put(Material.IRON_AXE, MODIFIES_BLOCKS);
@@ -538,9 +546,13 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.GLOWSTONE_DUST, 0);
MATERIAL_FLAGS.put(Material.COD, 0);
MATERIAL_FLAGS.put(Material.COOKED_COD, 0);
MATERIAL_FLAGS.put(Material.INK_SAC, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.INK_SAC, 0);
MATERIAL_FLAGS.put(Material.BLACK_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.BLUE_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.BROWN_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.CYAN_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.GRAY_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.GREEN_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.LIGHT_BLUE_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.LIGHT_GRAY_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.LIME_DYE, MODIFIES_BLOCKS);
@@ -548,7 +560,10 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.ORANGE_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.PINK_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.PURPLE_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.COCOA_BEANS, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.RED_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.WHITE_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.YELLOW_DYE, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.COCOA_BEANS, 0);
MATERIAL_FLAGS.put(Material.BONE_MEAL, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.BONE, 0);
MATERIAL_FLAGS.put(Material.SUGAR, 0);
@@ -622,6 +637,7 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.RABBIT_FOOT, 0);
MATERIAL_FLAGS.put(Material.RABBIT_HIDE, 0);
MATERIAL_FLAGS.put(Material.ARMOR_STAND, 0);
MATERIAL_FLAGS.put(Material.LEATHER_HORSE_ARMOR, 0);
MATERIAL_FLAGS.put(Material.IRON_HORSE_ARMOR, 0);
MATERIAL_FLAGS.put(Material.GOLDEN_HORSE_ARMOR, 0);
MATERIAL_FLAGS.put(Material.DIAMOND_HORSE_ARMOR, 0);
@@ -667,18 +683,25 @@ public final class Materials {
MATERIAL_FLAGS.put(Material.TROPICAL_FISH, 0);
MATERIAL_FLAGS.put(Material.TROPICAL_FISH_BUCKET, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_11, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_13, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_BLOCKS, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_CAT, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_CHIRP, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_FAR, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_MALL, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_MELLOHI, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_STAL, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_STRAD, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_WAIT, 0);
MATERIAL_FLAGS.put(Material.MUSIC_DISC_WARD, 0);
MATERIAL_FLAGS.put(Material.CREEPER_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.FLOWER_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.GLOBE_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.MOJANG_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.SKULL_BANNER_PATTERN, 0);
MATERIAL_FLAGS.put(Material.CROSSBOW, 0);
MATERIAL_FLAGS.put(Material.SUSPICIOUS_STEW, 0);
MATERIAL_FLAGS.put(Material.SWEET_BERRIES, 0);
// 1.15
try {
MATERIAL_FLAGS.put(Material.BEEHIVE, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.BEE_NEST, MODIFIED_ON_RIGHT);
MATERIAL_FLAGS.put(Material.HONEY_BLOCK, 0);
MATERIAL_FLAGS.put(Material.HONEYCOMB_BLOCK, 0);
MATERIAL_FLAGS.put(Material.HONEY_BOTTLE, 0);
MATERIAL_FLAGS.put(Material.HONEYCOMB, 0);
} catch (NoSuchFieldError ignored) {
}
// Fake tags
for (Material m : shulkerBoxes) {
@@ -728,6 +751,24 @@ public final class Materials {
for (Material pot : Tag.FLOWER_POTS.getValues()) {
MATERIAL_FLAGS.put(pot, MODIFIED_ON_RIGHT);
}
for (Material wall : Tag.WALLS.getValues()) {
MATERIAL_FLAGS.put(wall, 0);
}
for (Material sign : Tag.SIGNS.getValues()) {
MATERIAL_FLAGS.put(sign, 0);
}
for (Material flower : Tag.SMALL_FLOWERS.getValues()) {
MATERIAL_FLAGS.put(flower, 0);
}
for (Material bed : Tag.BEDS.getValues()) {
MATERIAL_FLAGS.put(bed, MODIFIED_ON_RIGHT);
}
for (Material musicDisc : Tag.ITEMS_MUSIC_DISCS.getValues()) {
MATERIAL_FLAGS.put(musicDisc, 0);
}
for (Material bannerPat : Tag.ITEMS_BANNERS.getValues()) {
MATERIAL_FLAGS.put(bannerPat, 0);
}
Stream.concat(Stream.concat(
Tag.CORAL_BLOCKS.getValues().stream(),
Tag.CORALS.getValues().stream()),
@@ -739,57 +780,51 @@ public final class Materials {
}
});
try {
MATERIAL_FLAGS.put(Material.SIGN, 0);
MATERIAL_FLAGS.put(Material.WALL_SIGN, 0);
MATERIAL_FLAGS.put(Material.DANDELION_YELLOW, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.ROSE_RED, MODIFIES_BLOCKS);
MATERIAL_FLAGS.put(Material.CACTUS_GREEN, MODIFIES_BLOCKS);
} catch (NoSuchFieldError ignored) { // missing fields in 1.14
}
// Check for missing items/blocks
for (Material material : Material.values()) {
//noinspection deprecation
if (material.isLegacy()) continue;
// Add spawn eggs
if (isSpawnEgg(material)) {
MATERIAL_FLAGS.put(material, 0);
} else if (isBed(material)) {
MATERIAL_FLAGS.put(material, MODIFIED_ON_RIGHT);
}
if (!MATERIAL_FLAGS.containsKey(material)) {
logger.fine("Missing material definition for " + (material.isBlock() ? "block " : "item ") + material.name());
MATERIAL_FLAGS.put(material, MODIFIED_ON_LEFT | MODIFIED_ON_RIGHT);
}
}
//DAMAGE_EFFECTS.add(PotionEffectType.ABSORPTION);
DAMAGE_EFFECTS.add(PotionEffectType.BLINDNESS);
DAMAGE_EFFECTS.add(PotionEffectType.CONFUSION);
//DAMAGE_EFFECTS.add(PotionEffectType.DAMAGE_RESISTANCE);
//DAMAGE_EFFECTS.add(PotionEffectType.FAST_DIGGING);
//DAMAGE_EFFECTS.add(PotionEffectType.FIRE_RESISTANCE);
DAMAGE_EFFECTS.add(PotionEffectType.HARM);
//DAMAGE_EFFECTS.add(PotionEffectType.HEAL);
//DAMAGE_EFFECTS.add(PotionEffectType.HEALTH_BOOST);
DAMAGE_EFFECTS.add(PotionEffectType.HUNGER);
//DAMAGE_EFFECTS.add(PotionEffectType.INCREASE_DAMAGE);
//DAMAGE_EFFECTS.add(PotionEffectType.INVISIBILITY);
//DAMAGE_EFFECTS.add(PotionEffectType.JUMP);
//DAMAGE_EFFECTS.add(PotionEffectType.NIGHT_VISION);
DAMAGE_EFFECTS.add(PotionEffectType.POISON);
//DAMAGE_EFFECTS.add(PotionEffectType.REGENERATION);
//DAMAGE_EFFECTS.add(PotionEffectType.SATURATION);
// DAMAGE_EFFECTS.add(PotionEffectType.SPEED);
DAMAGE_EFFECTS.add(PotionEffectType.SLOW);
// DAMAGE_EFFECTS.add(PotionEffectType.FAST_DIGGING);
DAMAGE_EFFECTS.add(PotionEffectType.SLOW_DIGGING);
//DAMAGE_EFFECTS.add(PotionEffectType.SPEED);
//DAMAGE_EFFECTS.add(PotionEffectType.WATER_BREATHING);
// DAMAGE_EFFECTS.add(PotionEffectType.INCREASE_DAMAGE);
// DAMAGE_EFFECTS.add(PotionEffectType.HEAL);
DAMAGE_EFFECTS.add(PotionEffectType.HARM);
// DAMAGE_EFFECTS.add(PotionEffectType.JUMP);
DAMAGE_EFFECTS.add(PotionEffectType.CONFUSION);
// DAMAGE_EFFECTS.add(PotionEffectType.REGENERATION);
// DAMAGE_EFFECTS.add(PotionEffectType.DAMAGE_RESISTANCE);
// DAMAGE_EFFECTS.add(PotionEffectType.FIRE_RESISTANCE);
// DAMAGE_EFFECTS.add(PotionEffectType.WATER_BREATHING);
// DAMAGE_EFFECTS.add(PotionEffectType.INVISIBILITY);
DAMAGE_EFFECTS.add(PotionEffectType.BLINDNESS);
// DAMAGE_EFFECTS.add(PotionEffectType.NIGHT_VISION);
DAMAGE_EFFECTS.add(PotionEffectType.HUNGER);
DAMAGE_EFFECTS.add(PotionEffectType.WEAKNESS);
DAMAGE_EFFECTS.add(PotionEffectType.POISON);
DAMAGE_EFFECTS.add(PotionEffectType.WITHER);
DAMAGE_EFFECTS.add(PotionEffectType.LEVITATION); // considered by game so I guess
// DAMAGE_EFFECTS.add(PotionEffectType.HEALTH_BOOST);
// DAMAGE_EFFECTS.add(PotionEffectType.ABSORPTION);
// DAMAGE_EFFECTS.add(PotionEffectType.SATURATION);
DAMAGE_EFFECTS.add(PotionEffectType.GLOWING);
DAMAGE_EFFECTS.add(PotionEffectType.LEVITATION);
// DAMAGE_EFFECTS.add(PotionEffectType.LUCK);
DAMAGE_EFFECTS.add(PotionEffectType.UNLUCK);
// DAMAGE_EFFECTS.add(PotionEffectType.SLOW_FALLING);
// DAMAGE_EFFECTS.add(PotionEffectType.CONDUIT_POWER);
// DAMAGE_EFFECTS.add(PotionEffectType.DOLPHINS_GRACE);
DAMAGE_EFFECTS.add(PotionEffectType.BAD_OMEN);
// DAMAGE_EFFECTS.add(PotionEffectType.HERO_OF_THE_VILLAGE);
}
private Materials() {
@@ -835,7 +870,6 @@ public final class Materials {
case LAVA_BUCKET:
return Material.LAVA;
case WATER_BUCKET:
return Material.WATER;
default:
return Material.WATER;
}
@@ -878,7 +912,7 @@ public final class Materials {
* @return true if a water block
*/
public static boolean isWater(Material material) {
return material == Material.WATER;
return material == Material.WATER || material == Material.BUBBLE_COLUMN;
}
/**
@@ -920,7 +954,8 @@ public final class Materials {
*/
public static boolean isPistonBlock(Material material) {
return material == Material.PISTON
|| material == Material.STICKY_PISTON;
|| material == Material.STICKY_PISTON
|| material == Material.MOVING_PISTON;
}
/**
@@ -937,6 +972,7 @@ public final class Materials {
|| material == Material.FURNACE_MINECART
|| material == Material.CHEST_MINECART;
}
/**
* Test whether the given material is a Boat.
*
@@ -962,14 +998,19 @@ public final class Materials {
|| material == Material.TRAPPED_CHEST
|| material == Material.HOPPER
|| material == Material.DROPPER
|| material == Material.BARREL
|| material == Material.BLAST_FURNACE
|| material == Material.SMOKER
|| shulkerBoxes.contains(material);
}
public static boolean isSpawnEgg(Material material) {
switch(material) {
switch (material) {
case SPIDER_SPAWN_EGG:
case BAT_SPAWN_EGG:
case BEE_SPAWN_EGG:
case BLAZE_SPAWN_EGG:
case CAT_SPAWN_EGG:
case CAVE_SPIDER_SPAWN_EGG:
case CHICKEN_SPAWN_EGG:
case COD_SPAWN_EGG:
@@ -982,6 +1023,7 @@ public final class Materials {
case ENDERMAN_SPAWN_EGG:
case ENDERMITE_SPAWN_EGG:
case EVOKER_SPAWN_EGG:
case FOX_SPAWN_EGG:
case GHAST_SPAWN_EGG:
case GUARDIAN_SPAWN_EGG:
case HORSE_SPAWN_EGG:
@@ -991,12 +1033,15 @@ public final class Materials {
case MOOSHROOM_SPAWN_EGG:
case MULE_SPAWN_EGG:
case OCELOT_SPAWN_EGG:
case PANDA_SPAWN_EGG:
case PARROT_SPAWN_EGG:
case PHANTOM_SPAWN_EGG:
case PIG_SPAWN_EGG:
case PILLAGER_SPAWN_EGG:
case POLAR_BEAR_SPAWN_EGG:
case PUFFERFISH_SPAWN_EGG:
case RABBIT_SPAWN_EGG:
case RAVAGER_SPAWN_EGG:
case SALMON_SPAWN_EGG:
case SHEEP_SPAWN_EGG:
case SHULKER_SPAWN_EGG:
@@ -1006,11 +1051,13 @@ public final class Materials {
case SLIME_SPAWN_EGG:
case SQUID_SPAWN_EGG:
case STRAY_SPAWN_EGG:
case TRADER_LLAMA_SPAWN_EGG:
case TROPICAL_FISH_SPAWN_EGG:
case TURTLE_SPAWN_EGG:
case VEX_SPAWN_EGG:
case VILLAGER_SPAWN_EGG:
case VINDICATOR_SPAWN_EGG:
case WANDERING_TRADER_SPAWN_EGG:
case WITCH_SPAWN_EGG:
case WITHER_SKELETON_SPAWN_EGG:
case WOLF_SPAWN_EGG:
@@ -1030,8 +1077,12 @@ public final class Materials {
return EntityType.SPIDER;
case BAT_SPAWN_EGG:
return EntityType.BAT;
case BEE_SPAWN_EGG:
return EntityType.BEE;
case BLAZE_SPAWN_EGG:
return EntityType.BLAZE;
case CAT_SPAWN_EGG:
return EntityType.CAT;
case CAVE_SPIDER_SPAWN_EGG:
return EntityType.CAVE_SPIDER;
case CHICKEN_SPAWN_EGG:
@@ -1056,6 +1107,8 @@ public final class Materials {
return EntityType.ENDERMITE;
case EVOKER_SPAWN_EGG:
return EntityType.EVOKER;
case FOX_SPAWN_EGG:
return EntityType.FOX;
case GHAST_SPAWN_EGG:
return EntityType.GHAST;
case GUARDIAN_SPAWN_EGG:
@@ -1074,18 +1127,22 @@ public final class Materials {
return EntityType.MULE;
case OCELOT_SPAWN_EGG:
return EntityType.OCELOT;
case PANDA_SPAWN_EGG:
return EntityType.PANDA;
case PARROT_SPAWN_EGG:
return EntityType.PARROT;
case PHANTOM_SPAWN_EGG:
return EntityType.PHANTOM;
case PIG_SPAWN_EGG:
return EntityType.PIG;
case PILLAGER_SPAWN_EGG:
return EntityType.PILLAGER;
case POLAR_BEAR_SPAWN_EGG:
return EntityType.POLAR_BEAR;
case PUFFERFISH_SPAWN_EGG:
return EntityType.PUFFERFISH;
case RABBIT_SPAWN_EGG:
return EntityType.RABBIT;
case RAVAGER_SPAWN_EGG:
return EntityType.RAVAGER;
case SALMON_SPAWN_EGG:
return EntityType.SALMON;
case SHEEP_SPAWN_EGG:
@@ -1104,6 +1161,8 @@ public final class Materials {
return EntityType.SQUID;
case STRAY_SPAWN_EGG:
return EntityType.STRAY;
case TRADER_LLAMA_SPAWN_EGG:
return EntityType.TRADER_LLAMA;
case TROPICAL_FISH_SPAWN_EGG:
return EntityType.TROPICAL_FISH;
case TURTLE_SPAWN_EGG:
@@ -1114,6 +1173,8 @@ public final class Materials {
return EntityType.VILLAGER;
case VINDICATOR_SPAWN_EGG:
return EntityType.VINDICATOR;
case WANDERING_TRADER_SPAWN_EGG:
return EntityType.WANDERING_TRADER;
case WITCH_SPAWN_EGG:
return EntityType.WITCH;
case WITHER_SKELETON_SPAWN_EGG:
@@ -1128,33 +1189,14 @@ public final class Materials {
return EntityType.ZOMBIE;
case ZOMBIE_VILLAGER_SPAWN_EGG:
return EntityType.ZOMBIE_VILLAGER;
default:
return EntityType.PIG; // Uhhh
case PIG_SPAWN_EGG:
default: // Uhh
return EntityType.PIG;
}
}
public static boolean isBed(Material material) {
switch (material) {
case BLACK_BED:
case BLUE_BED:
case BROWN_BED:
case CYAN_BED:
case GRAY_BED:
case GREEN_BED:
case LIGHT_BLUE_BED:
case LIGHT_GRAY_BED:
case LIME_BED:
case MAGENTA_BED:
case ORANGE_BED:
case PINK_BED:
case PURPLE_BED:
case RED_BED:
case WHITE_BED:
case YELLOW_BED:
return true;
default:
return false;
}
return Tag.BEDS.isTagged(material);
}
/**
@@ -1170,7 +1212,11 @@ public final class Materials {
|| type == Material.MELON_STEM
|| type == Material.PUMPKIN_STEM
|| type == Material.PUMPKIN
|| type == Material.MELON;
|| type == Material.MELON
|| type == Material.CACTUS
|| type == Material.SUGAR_CANE
|| type == Material.BAMBOO
|| type == Material.BAMBOO_SAPLING;
}
/**
@@ -1185,28 +1231,33 @@ public final class Materials {
*/
public static boolean isUseFlagApplicable(Material material) {
if (Tag.BUTTONS.isTagged(material)
|| Tag.DOORS.isTagged(material)
|| Tag.WOODEN_PRESSURE_PLATES.isTagged(material)
|| Tag.WOODEN_TRAPDOORS.isTagged(material)) {
|| Tag.DOORS.isTagged(material)
|| Tag.WOODEN_PRESSURE_PLATES.isTagged(material)
|| Tag.WOODEN_TRAPDOORS.isTagged(material)) {
return true;
}
switch (material) {
case LEVER: return true;
case TRIPWIRE: return true;
case ENCHANTING_TABLE: return true;
case BEACON: return true;
case ANVIL: return true;
case DAMAGED_ANVIL: return true;
case CHIPPED_ANVIL: return true;
case STONE_PRESSURE_PLATE: return true;
case HEAVY_WEIGHTED_PRESSURE_PLATE: return true;
case LIGHT_WEIGHTED_PRESSURE_PLATE: return true;
case OAK_FENCE_GATE: return true;
case SPRUCE_FENCE_GATE: return true;
case BIRCH_FENCE_GATE: return true;
case JUNGLE_FENCE_GATE: return true;
case DARK_OAK_FENCE_GATE: return true;
case ACACIA_FENCE_GATE: return true;
case LEVER:
case LECTERN:
case ACACIA_FENCE_GATE:
case DARK_OAK_FENCE_GATE:
case JUNGLE_FENCE_GATE:
case BIRCH_FENCE_GATE:
case SPRUCE_FENCE_GATE:
case OAK_FENCE_GATE:
case LIGHT_WEIGHTED_PRESSURE_PLATE:
case HEAVY_WEIGHTED_PRESSURE_PLATE:
case STONE_PRESSURE_PLATE:
case ANVIL:
case DAMAGED_ANVIL:
case CHIPPED_ANVIL:
case ENCHANTING_TABLE:
case BELL:
case LOOM:
case CARTOGRAPHY_TABLE:
case STONECUTTER:
case GRINDSTONE:
return true;
default: return false;
}
}
@@ -1305,7 +1356,8 @@ public final class Materials {
case GOLDEN_CHESTPLATE:
case GOLDEN_LEGGINGS:
case GOLDEN_BOOTS:
//case TURTLE_HELMET:
case TURTLE_HELMET:
case ELYTRA:
return true;
default:
return false;
@@ -30,13 +30,8 @@ public class ServerReport extends DataReport {
Server server = Bukkit.getServer();
try {
append("Server ID", server.getServerId());
append("Server Name", server.getServerName());
} catch (NoSuchMethodError ignored) {
}
append("Bukkit Version", server.getBukkitVersion());
append("Implementation", server.getVersion());
append("Implementation", server.getName() + " " + server.getVersion());
append("Player Count", "%d/%d", Bukkit.getOnlinePlayers().size(), server.getMaxPlayers());
append("Server Class Source", server.getClass().getProtectionDomain().getCodeSource().getLocation());
@@ -0,0 +1,57 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util.profile.resolver;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.sk89q.worldguard.util.profile.Profile;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import javax.annotation.Nullable;
public final class PaperProfileService extends SingleRequestService {
private static final PaperProfileService INSTANCE = new PaperProfileService();
private PaperProfileService() {
if (!PaperLib.isPaper()) {
throw new IllegalStateException("Attempt to access PaperProfileService on non-Paper server.");
}
}
@Override
public int getIdealRequestLimit() {
return Integer.MAX_VALUE;
}
@Override
@Nullable
public Profile findByName(String name) {
PlayerProfile profile = Bukkit.createProfile(name);
if (profile.completeFromCache()) {
//noinspection ConstantConditions - completeFromCache guarantees non-null on success
return new Profile(profile.getId(), profile.getName());
}
return null;
}
public static PaperProfileService getInstance() {
return INSTANCE;
}
}
@@ -7,7 +7,7 @@
###############################################################################
#
# Example to block some ore mining and placement:
# [coalore,goldore,ironore]
# [coal_ore,gold_ore,iron_ore]
# on-break=deny,log,kick
# on-place=deny,tell
#
@@ -42,7 +42,7 @@
###############################################################################
#
# For more information, see:
# https://worldguard.readthedocs.io/en/latest/blacklist/
# https://worldguard.enginehub.org/en/latest/blacklist/
#
###############################################################################
#
@@ -51,17 +51,12 @@
#
# Deny lava buckets
#[lavabucket]
#[lava_bucket]
#ignore-perms=my.own.madeup.permission
#ignore-groups=admins,mods
#on-use=deny,tell
# Deny some ore
#[coalore,goldore,ironore]
#[coal_ore,gold_ore,iron_ore]
#ignore-groups=admins,mods
#on-break=notify,deny,log
# Some funky data value tests
#[wood:0;>=2]
#ignore-groups=admins,mods
#on-break=notify,deny,log
@@ -1,6 +1,6 @@
name: WorldGuard
main: com.sk89q.worldguard.bukkit.WorldGuardPlugin
version: "${project.internalVersion}"
version: "${internalVersion}"
depend: [WorldEdit]
softdepend: [CommandBook]
api-version: 1.13
-30
View File
@@ -1,30 +0,0 @@
apply plugin: 'eclipse'
apply plugin: 'idea'
dependencies {
api 'com.sk89q.worldedit:worldedit-core:7.0.1-SNAPSHOT'
implementation 'com.sk89q:squirrelid:0.2.0'
implementation 'org.flywaydb:flyway-core:3.0'
implementation 'org.khelekore:prtree:1.5.0'
api 'com.google.code.findbugs:jsr305:1.3.9'
testImplementation 'junit:junit:4.11'
testImplementation 'org.hamcrest:hamcrest-library:1.2.1'
}
sourceSets {
main {
java {
srcDir 'src/main/java'
}
resources {
srcDir 'src/main/resources'
}
}
}
shadowJar {
relocate('com.sk89q.squirrelid', 'com.sk89q.worldguard.util.profile')
}
build.dependsOn(shadowJar { classifier = null })
+31
View File
@@ -0,0 +1,31 @@
plugins {
id("java-library")
id("net.ltgt.apt-eclipse")
id("net.ltgt.apt-idea")
}
applyPlatformAndCoreConfiguration()
dependencies {
"compile"(project(":worldguard-libs:core"))
"compile"("com.sk89q.worldedit:worldedit-core:${Versions.WORLDEDIT}")
"implementation"("org.flywaydb:flyway-core:3.0")
"compileOnly"("com.google.code.findbugs:jsr305:1.3.9")
"testImplementation"("org.hamcrest:hamcrest-library:1.2.1")
}
tasks.withType<JavaCompile>().configureEach {
dependsOn(":worldguard-libs:build")
}
sourceSets {
main {
java {
srcDir("src/main/java")
}
resources {
srcDir("src/main/resources")
}
}
}
@@ -31,6 +31,29 @@ import java.util.List;
public interface LocalPlayer extends Player, RegionAssociable {
/**
* Returns the default namespace for this player.
*
* @return the default namespace.
*/
String getDefaultNamespace();
default boolean isDefaultNamespace(String otherNamespace) {
String namespace = getDefaultNamespace();
// If both are null, they're the same (the global)
if (namespace == null && otherNamespace == null) {
return true;
}
// If only one is null, they're a mismatch
if (namespace == null || otherNamespace == null) {
return false;
}
// Compare string equality
return namespace.equalsIgnoreCase(otherNamespace);
}
/**
* Returns true if this player is inside a group.
*
@@ -207,4 +230,17 @@ public interface LocalPlayer extends Player, RegionAssociable {
*/
@Beta
void sendTitle(String title, String subtitle);
/**
* Clears fall distance.
*/
void resetFallDistance();
/**
* Teleport the player, potentially async, displaying the message on a success.
* @param location location to teleport to
* @param successMessage message to display on success
* @param failMessage message to display on failure
*/
void teleport(Location location, String successMessage, String failMessage);
}
@@ -24,14 +24,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.squirrelid.cache.HashMapCache;
import com.sk89q.squirrelid.cache.ProfileCache;
import com.sk89q.squirrelid.cache.SQLiteCache;
import com.sk89q.squirrelid.resolver.BukkitPlayerService;
import com.sk89q.squirrelid.resolver.CacheForwardingService;
import com.sk89q.squirrelid.resolver.CombinedProfileService;
import com.sk89q.squirrelid.resolver.HttpRepositoryService;
import com.sk89q.squirrelid.resolver.ProfileService;
import com.sk89q.worldguard.util.profile.cache.HashMapCache;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.cache.SQLiteCache;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.task.SimpleSupervisor;
import com.sk89q.worldedit.util.task.Supervisor;
@@ -77,23 +73,20 @@ public final class WorldGuard {
}
public void setup() {
executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20));
executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20,
"WorldGuard Task Executor - %s"));
File cacheDir = new File(getPlatform().getConfigDir().toFile(), "cache");
cacheDir.mkdirs();
try {
profileCache = new SQLiteCache(new File(cacheDir, "profiles.sqlite"));
} catch (IOException e) {
logger.log(Level.WARNING, "Failed to initialize SQLite profile cache");
} catch (IOException | UnsatisfiedLinkError ignored) {
logger.log(Level.WARNING, "Failed to initialize SQLite profile cache. Cache is memory-only.");
profileCache = new HashMapCache();
}
profileService = new CacheForwardingService(
new CombinedProfileService(
BukkitPlayerService.getInstance(),
HttpRepositoryService.forMinecraft()),
profileCache);
profileService = getPlatform().createProfileService(profileCache);
getPlatform().load();
}
@@ -24,7 +24,9 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.serializer.legacy.LegacyComponentSerializer;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Command-related utility methods.
@@ -76,7 +78,12 @@ public final class CommandUtils {
str = str.replace("`x", "&r");
// MC classic
str = LegacyComponentSerializer.INSTANCE.serialize(LegacyComponentSerializer.INSTANCE.deserialize(str, '&'));
// FIXME: workaround for https://github.com/KyoriPowered/text/issues/50
// remove when fixed upstream and updated in WorldEdit
str = Arrays.stream(str.split("\n")).map(line -> {
TextComponent comp = LegacyComponentSerializer.INSTANCE.deserialize(line, '&');
return LegacyComponentSerializer.INSTANCE.serialize(comp);
}).collect(Collectors.joining("\n"));
return str;
}
@@ -52,12 +52,13 @@ import com.sk89q.worldguard.util.profiler.SamplerBuilder;
import com.sk89q.worldguard.util.profiler.SamplerBuilder.Sampler;
import com.sk89q.worldguard.util.profiler.ThreadIdFilter;
import com.sk89q.worldguard.util.profiler.ThreadNameFilter;
import com.sk89q.worldguard.util.report.ApplicableRegionsReport;
import com.sk89q.worldguard.util.report.ConfigReport;
import java.io.File;
import java.io.IOException;
import java.lang.management.ThreadInfo;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@@ -130,11 +131,14 @@ public class WorldGuardCommands {
worldGuard.getPlatform().addPlatformReports(report);
report.add(new SystemInfoReport());
report.add(new ConfigReport());
if (sender instanceof LocalPlayer) {
report.add(new ApplicableRegionsReport((LocalPlayer) sender));
}
String result = report.toString();
try {
File dest = new File(worldGuard.getPlatform().getConfigDir().toFile(), "report.txt");
Files.write(result, dest, Charset.forName("UTF-8"));
Files.write(result, dest, StandardCharsets.UTF_8);
sender.print("WorldGuard report written to " + dest.getAbsolutePath());
} catch (IOException e) {
throw new CommandException("Failed to write report: " + e.getMessage());
@@ -196,7 +200,7 @@ public class WorldGuardCommands {
synchronized (this) {
if (activeSampler != null) {
throw new CommandException("A profile is currently in progress! Please use /wg stopprofile to stop the current profile.");
throw new CommandException("A profile is currently in progress! Please use /wg stopprofile to cancel the current profile.");
}
SamplerBuilder builder = new SamplerBuilder();
@@ -206,10 +210,12 @@ public class WorldGuardCommands {
sampler = activeSampler = builder.start();
}
sender.print(TextComponent.of("Starting CPU profiling. Use ", TextColor.LIGHT_PURPLE)
sender.print(TextComponent.of("Starting CPU profiling. Results will be available in " + minutes + " minutes.", TextColor.LIGHT_PURPLE)
.append(TextComponent.newline())
.append(TextComponent.of("Use ", TextColor.GRAY))
.append(TextComponent.of("/wg stopprofile", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/wg stopprofile")))
.append(TextComponent.of(" to stop profiling.", TextColor.LIGHT_PURPLE)));
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/wg stopprofile")))
.append(TextComponent.of(" at any time to cancel CPU profiling.", TextColor.GRAY)));
worldGuard.getSupervisor().monitor(FutureForwardingTask.create(
sampler.getFuture(), "CPU profiling for " + minutes + " minutes", sender));
@@ -227,7 +233,7 @@ public class WorldGuardCommands {
try {
File dest = new File(worldGuard.getPlatform().getConfigDir().toFile(), "profile.txt");
Files.write(output, dest, Charset.forName("UTF-8"));
Files.write(output, dest, StandardCharsets.UTF_8);
sender.print("CPU profiling data written to " + dest.getAbsolutePath());
} catch (IOException e) {
sender.printError("Failed to write CPU profiling data: " + e.getMessage());
@@ -256,7 +262,7 @@ public class WorldGuardCommands {
activeSampler = null;
}
sender.print("The running CPU profile has been stopped.");
sender.print("The running CPU profile has been cancelled.");
}
@Command(aliases = {"flushstates", "clearstates"},
@@ -38,11 +38,10 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.internal.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.flags.BooleanFlag;
import com.sk89q.worldguard.protection.flags.DoubleFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.IntegerFlag;
import com.sk89q.worldguard.protection.flags.LocationFlag;
import com.sk89q.worldguard.protection.flags.NumberFlag;
import com.sk89q.worldguard.protection.flags.RegistryFlag;
import com.sk89q.worldguard.protection.flags.SetFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
@@ -76,13 +75,15 @@ class FlagHelperBox extends PaginationBox {
.collect(Collectors.toList());
private static final int SIZE = FLAGS.size() == Flags.INBUILT_FLAGS.size() ? FLAGS.size() : FLAGS.size() + 1;
private static final int PAD_PX_SIZE = 180;
private static final Set<Flag<?>> DANGER_ZONE = ImmutableSet.of(Flags.BUILD, Flags.PASSTHROUGH, Flags.BLOCK_PLACE, Flags.BLOCK_BREAK);
private final World world;
private final ProtectedRegion region;
private final RegionPermissionModel perms;
private boolean monoSpace;
FlagHelperBox(World world, ProtectedRegion region, RegionPermissionModel perms) {
super("Flags for " + region.getId(), "/rg flags -w " + world.getName() + " -p %page% " + region.getId());
super("Flags for " + region.getId(), "/rg flags -w \"" + world.getName() + "\" -p %page% " + region.getId());
this.world = world;
this.region = region;
this.perms = perms;
@@ -114,25 +115,25 @@ class FlagHelperBox extends PaginationBox {
private void appendFlagName(TextComponent.Builder builder, Flag<?> flag, TextColor color) {
final String name = flag.getName();
int length = FlagFontInfo.getPxLength(name);
int length = monoSpace ? name.length() : FlagFontInfo.getPxLength(name);
builder.append(TextComponent.of(name, color));
if (flag.usesMembershipAsDefault()) {
builder.append(TextComponent.empty().append(TextComponent.of("*", TextColor.AQUA))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("This is a special flag which defaults to allow for members, and deny for non-members"))));
length += FlagFontInfo.getPxLength('*');
length += monoSpace ? 1 : FlagFontInfo.getPxLength('*');
}
if (flag == Flags.PASSTHROUGH) {
builder.append(TextComponent.empty().append(TextComponent.of("*", TextColor.AQUA))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("This is a special flag which overrides build checks. (Not movement related!)"))));
length += FlagFontInfo.getPxLength('*');
length += monoSpace ? 1 : FlagFontInfo.getPxLength('*');
}
int leftover = PAD_PX_SIZE - length;
int leftover = (monoSpace ? PAD_PX_SIZE / 3 : PAD_PX_SIZE) - length;
builder.append(TextComponent.space());
leftover -= 4;
if (leftover > 0) {
builder.append(TextComponent.of(Strings.repeat(".", leftover / 2), TextColor.DARK_GRAY));
builder.append(TextComponent.of(Strings.repeat(".", monoSpace ? leftover : leftover / 2), TextColor.DARK_GRAY));
}
}
@@ -149,10 +150,8 @@ class FlagHelperBox extends PaginationBox {
appendStringFlagValue(builder, ((StringFlag) flag));
} else if (flag instanceof LocationFlag) {
appendLocationFlagValue(builder, ((LocationFlag) flag));
} else if (flag instanceof IntegerFlag) {
appendNumericFlagValue(builder, (IntegerFlag) flag);
} else if (flag instanceof DoubleFlag) {
appendNumericFlagValue(builder, (DoubleFlag) flag);
} else if (flag instanceof NumberFlag) {
appendNumericFlagValue(builder, (NumberFlag<? extends Number>) flag);
} else {
String display = String.valueOf(region.getFlag(flag));
if (display.length() > 23) {
@@ -200,7 +199,13 @@ class FlagHelperBox extends PaginationBox {
if (maySet) {
if (isExplicitSet) {
hoverTexts.add(TextComponent.of("Click to unset", TextColor.GOLD));
} else if (flag != Flags.BUILD && flag != Flags.PASSTHROUGH) {
} else if (DANGER_ZONE.contains(flag)) {
hoverTexts.add(TextComponent.of("Setting this flag may have unintended consequences.", TextColor.RED)
.append(TextComponent.newline())
.append(TextComponent.of("Please read the documentation and set this flag manually if you really intend to.")
.append(TextComponent.newline())
.append(TextComponent.of("(Hint: You do not need to set this to protect the region!)"))));
} else {
hoverTexts.add(TextComponent.of("Click to set", TextColor.GOLD));
}
}
@@ -221,7 +226,7 @@ class FlagHelperBox extends PaginationBox {
HoverEvent.of(HoverEvent.Action.SHOW_TEXT, hoverBuilder.build()));
}
if (maySet && (isExplicitSet || flag != Flags.BUILD && flag != Flags.PASSTHROUGH)) {
if (maySet && (isExplicitSet || !DANGER_ZONE.contains(flag))) {
builder.append(choiceComponent.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
makeCommand(flag, isExplicitSet ? "" : choice))));
} else {
@@ -296,7 +301,7 @@ class FlagHelperBox extends PaginationBox {
}
private String makeCommand(Flag<?> flag, Object choice) {
return "/rg flag -w " + world.getName() + " -h " + getCurrentPage()
return "/rg flag -w \"" + world.getName() + "\" -h " + getCurrentPage()
+ " " + region.getId() + " " + flag.getName() + " " + choice;
}
@@ -397,13 +402,13 @@ class FlagHelperBox extends PaginationBox {
}
}
private <V extends Number> void appendNumericFlagValue(TextComponent.Builder builder, Flag<V> flag) {
private <V extends Number> void appendNumericFlagValue(TextComponent.Builder builder, NumberFlag<V> flag) {
Number currVal = region.getFlag(flag);
if (currVal == null) {
currVal = getInheritedValue(region, flag);
}
Number defVal = flag.getDefault();
Number[] suggested = getSuggestedNumbers(flag);
Number[] suggested = flag.getSuggestedValues();
SortedSet<Number> choices = new TreeSet<>(Comparator.comparing(Number::doubleValue));
if (currVal != null) {
choices.add(currVal);
@@ -418,19 +423,6 @@ class FlagHelperBox extends PaginationBox {
appendValueChoices(builder, flag, (Iterator<V>) choices.iterator(), choices.isEmpty() ? "unset number" : "[custom]");
}
private Number[] getSuggestedNumbers(Flag<? extends Number> flag) {
if (flag == Flags.HEAL_AMOUNT || flag == Flags.FEED_AMOUNT) {
return new Number[]{0, 5, 10, 20};
} else if (flag == Flags.MIN_FOOD || flag == Flags.MIN_HEAL) {
return new Number[]{0, 10};
} else if (flag == Flags.MAX_FOOD || flag == Flags.MAX_HEAL) {
return new Number[]{10, 20};
} else if (flag == Flags.HEAL_DELAY || flag == Flags.FEED_DELAY) {
return new Number[]{0, 1, 5};
}
return new Number[0];
}
private void appendStringFlagValue(TextComponent.Builder builder, StringFlag flag) {
String currVal = region.getFlag(flag);
if (currVal == null) {
@@ -479,6 +471,10 @@ class FlagHelperBox extends PaginationBox {
}
}
void tryMonoSpacing() {
this.monoSpace = true;
}
private static final class FlagFontInfo {
static int getPxLength(char c) {
switch (c) {
@@ -32,6 +32,7 @@ import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.protection.util.DomainInputResolver;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
@@ -50,13 +51,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:",
desc = "Add a member to a region",
min = 2)
public void addMember(CommandContext args, Actor sender) throws CommandException {
public void addMember(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
// Check permissions
if (!getPermissionModel(sender).mayAddMembers(region)) {
@@ -69,10 +70,11 @@ public class MemberCommands extends RegionCommandsBase {
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY);
final String description = String.format("Adding members to the region '%s' on '%s'", region.getId(), world.getName());
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding members to the region '%s' on '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(resolver, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new members.", region.getId()), region.getMembers()::addAll)
.onSuccess(String.format("Region '%s' updated with new members.", friendlyName), region.getMembers()::addAll)
.onFailure("Failed to add new members", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -82,15 +84,14 @@ public class MemberCommands extends RegionCommandsBase {
flags = "nw:",
desc = "Add an owner to a region",
min = 2)
public void addOwner(CommandContext args, Actor sender) throws CommandException {
public void addOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
// Check permissions
if (!getPermissionModel(sender).mayAddOwners(region)) {
@@ -103,10 +104,11 @@ public class MemberCommands extends RegionCommandsBase {
resolver.setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY);
final String description = String.format("Adding owners to the region '%s' on '%s'", region.getId(), world.getName());
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding owners to the region '%s' on '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(checkedAddOwners(sender, manager, region, world, resolver), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("Region '%s' updated with new owners.", region.getId()), region.getOwners()::addAll)
.onSuccess(String.format("Region '%s' updated with new owners.", friendlyName), region.getOwners()::addAll)
.onFailure("Failed to add new owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -149,13 +151,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "naw:",
desc = "Remove an owner to a region",
min = 1)
public void removeMember(CommandContext args, Actor sender) throws CommandException {
public void removeMember(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
// Check permissions
if (!getPermissionModel(sender).mayRemoveMembers(region)) {
@@ -178,11 +180,12 @@ public class MemberCommands extends RegionCommandsBase {
callable = resolver;
}
final String description = String.format("Removing members from the region '%s' on '%s'", region.getId(), world.getName());
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing members from the region '%s' on '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(callable, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... querying player names...)")
.onSuccess(String.format("Region '%s' updated with members removed.", region.getId()), region.getMembers()::removeAll)
.onSuccess(String.format("Region '%s' updated with members removed.", friendlyName), region.getMembers()::removeAll)
.onFailure("Failed to remove members", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -192,13 +195,13 @@ public class MemberCommands extends RegionCommandsBase {
flags = "naw:",
desc = "Remove an owner to a region",
min = 1)
public void removeOwner(CommandContext args, Actor sender) throws CommandException {
public void removeOwner(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
String id = args.getString(0);
RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, id, true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion region = checkExistingRegion(sender, manager, id);
// Check permissions
if (!getPermissionModel(sender).mayRemoveOwners(region)) {
@@ -221,11 +224,12 @@ public class MemberCommands extends RegionCommandsBase {
callable = resolver;
}
final String description = String.format("Removing owners from the region '%s' on '%s'", region.getId(), world.getName());
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing owners from the region '%s' on '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(callable, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... querying player names...)")
.onSuccess(String.format("Region '%s' updated with owners removed.", region.getId()), region.getOwners()::removeAll)
.onSuccess(String.format("Region '%s' updated with owners removed.", friendlyName), region.getOwners()::removeAll)
.onFailure("Failed to remove owners", worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -25,12 +25,14 @@ import com.google.common.collect.Sets;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.LabelFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
@@ -43,7 +45,6 @@ import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.commands.CommandUtils;
import com.sk89q.worldguard.commands.task.RegionAdder;
import com.sk89q.worldguard.commands.task.RegionLister;
import com.sk89q.worldguard.commands.task.RegionManagerLoader;
@@ -67,18 +68,17 @@ import com.sk89q.worldguard.protection.managers.migration.MigrationException;
import com.sk89q.worldguard.protection.managers.migration.UUIDMigration;
import com.sk89q.worldguard.protection.managers.storage.DriverType;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.*;
import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy;
import com.sk89q.worldguard.session.Session;
import com.sk89q.worldguard.util.Enums;
import com.sk89q.worldguard.util.logging.LoggerToChatHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -95,7 +95,29 @@ public final class RegionCommands extends RegionCommandsBase {
checkNotNull(worldGuard);
this.worldGuard = worldGuard;
}
private static TextComponent passthroughFlagWarning = TextComponent.empty()
.append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" This flag is unrelated to moving through regions."))
.append(TextComponent.newline())
.append(TextComponent.of("It overrides build checks. If you're unsure what this means, see ")
.append(TextComponent.of("[this documentation page]", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.OPEN_URL,
"https://worldguard.enginehub.org/en/latest/regions/flags/#overrides")))
.append(TextComponent.of(" for more info.")));
private static TextComponent buildFlagWarning = TextComponent.empty()
.append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" Setting this flag is not required for protection."))
.append(TextComponent.newline())
.append(TextComponent.of("Setting this flag will completely override default protection, and apply" +
" to members, non-members, pistons, sand physics, and everything else that can modify blocks."))
.append(TextComponent.newline())
.append(TextComponent.of("Only set this flag if you are sure you know what you are doing. See ")
.append(TextComponent.of("[this documentation page]", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.OPEN_URL,
"https://worldguard.enginehub.org/en/latest/regions/flags/#protection-related")))
.append(TextComponent.of(" for more info.")));
/**
* Defines a new region.
*
@@ -108,7 +130,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "ng",
desc = "Defines a region",
min = 1)
public void define(CommandContext args, Actor sender) throws CommandException {
public void define(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
@@ -117,11 +139,12 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException();
}
String id = checkRegionId(args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
World world = player.getWorld();
RegionManager manager = checkRegionManager(world);
checkRegionDoesNotExist(manager, id, true);
checkRegionDoesNotExist(sender, manager, id, true);
ProtectedRegion region;
@@ -129,18 +152,23 @@ public final class RegionCommands extends RegionCommandsBase {
region = new GlobalProtectedRegion(id);
} else {
region = checkRegionFromSelection(player, id);
warnAboutDimensions(player, region);
informNewUser(player, manager, region);
}
RegionAdder task = new RegionAdder(manager, region);
task.addOwnersFromCommand(args, 2);
final String description = String.format("Adding region '%s'", region.getId());
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Adding region '%s'", friendlyName);
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.onSuccess(String.format("A new region has been made named '%s'.", region.getId()), null)
.onFailure("Failed to add the region '%s'", worldGuard.getExceptionConverter())
.onSuccess((Component) null,
t -> {
sender.print(String.format("A new region has been made named '%s'.", friendlyName));
warnAboutDimensions(sender, region);
informNewUser(sender, manager, region);
checkSpawnOverlap(sender, world, region);
})
.onFailure(String.format("Failed to add the region '%s'", friendlyName), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -156,16 +184,17 @@ public final class RegionCommands extends RegionCommandsBase {
desc = "Re-defines the shape of a region",
flags = "g",
min = 1, max = 1)
public void redefine(CommandContext args, Actor sender) throws CommandException {
public void redefine(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
String id = checkRegionId(args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
World world = player.getWorld();
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, id, false);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions
if (!getPermissionModel(player).mayRedefine(existing)) {
@@ -178,20 +207,25 @@ public final class RegionCommands extends RegionCommandsBase {
region = new GlobalProtectedRegion(id);
} else {
region = checkRegionFromSelection(player, id);
warnAboutDimensions(player, region);
informNewUser(player, manager, region);
}
region.copyFrom(existing);
RegionAdder task = new RegionAdder(manager, region);
final String description = String.format("Updating region '%s'", region.getId());
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Updating region '%s'", friendlyName);
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess(String.format("Region '%s' has been updated with a new area.", region.getId()), null)
.onFailure(String.format("Failed to update the region '%s'", region.getId()), worldGuard.getExceptionConverter())
.onSuccess((Component) null,
t -> {
player.print(String.format("Region '%s' has been updated with a new area.", friendlyName));
warnAboutDimensions(player, region);
informNewUser(player, manager, region);
checkSpawnOverlap(sender, world, region);
})
.onFailure(String.format("Failed to update the region '%s'", friendlyName), worldGuard.getExceptionConverter())
.buildAndExec(worldGuard.getExecutorService());
}
@@ -209,7 +243,7 @@ public final class RegionCommands extends RegionCommandsBase {
usage = "<id>",
desc = "Claim a region",
min = 1, max = 1)
public void claim(CommandContext args, Actor sender) throws CommandException {
public void claim(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
LocalPlayer player = worldGuard.checkPlayer(sender);
@@ -220,11 +254,11 @@ public final class RegionCommands extends RegionCommandsBase {
throw new CommandPermissionsException();
}
String id = checkRegionId(args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
RegionManager manager = checkRegionManager(player.getWorld());
checkRegionDoesNotExist(manager, id, false);
checkRegionDoesNotExist(sender, manager, id, false);
ProtectedRegion region = checkRegionFromSelection(player, id);
WorldConfiguration wcfg = WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(player.getWorld());
@@ -286,11 +320,12 @@ public final class RegionCommands extends RegionCommandsBase {
task.setLocatorPolicy(UserLocatorPolicy.UUID_ONLY);
task.setOwnersInput(new String[]{player.getName()});
final String description = String.format("Claiming region '%s'", id);
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Claiming region '%s'", friendlyName);
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("(Please wait... " + description + ")")
.onSuccess(TextComponent.of(String.format("A new region has been claimed named '%s'.", id)), null)
.onSuccess(TextComponent.of(String.format("A new region has been claimed named '%s'.", friendlyName)), null)
.onFailure("Failed to claim region", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
}
@@ -306,7 +341,7 @@ public final class RegionCommands extends RegionCommandsBase {
usage = "[id]",
desc = "Load a region as a WorldEdit selection",
min = 0, max = 1)
public void select(CommandContext args, Actor sender) throws CommandException {
public void select(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
LocalPlayer player = worldGuard.checkPlayer(sender);
RegionManager manager = checkRegionManager(player.getWorld());
ProtectedRegion existing;
@@ -315,7 +350,8 @@ public final class RegionCommands extends RegionCommandsBase {
if (args.argsLength() == 0) {
existing = checkRegionStandingIn(manager, player, "/rg select %id%");
} else {
existing = checkExistingRegion(manager, args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
existing = checkExistingRegion(sender, manager, id);
}
// Check permissions
@@ -339,7 +375,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "usw:",
desc = "Get information about a region",
min = 0, max = 1)
public void info(CommandContext args, Actor sender) throws CommandException {
public void info(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -355,9 +391,10 @@ public final class RegionCommands extends RegionCommandsBase {
}
existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg info -w " + world.getName() + " %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
"/rg info -w \"" + world.getName() + "\" %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
} else { // Get region from the ID
existing = checkExistingRegion(manager, args.getString(0), true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
existing = checkExistingRegion(sender, manager, id);
}
// Check permissions
@@ -453,7 +490,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "g:w:eh:",
desc = "Set flags",
min = 2)
public void flag(CommandContext args, Actor sender) throws CommandException {
public void flag(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -471,14 +508,10 @@ public final class RegionCommands extends RegionCommandsBase {
value = "";
}
// Add color codes
if (value != null) {
value = CommandUtils.replaceColorMacros(value);
}
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions
if (!permModel.maySetFlag(existing)) {
@@ -490,71 +523,23 @@ public final class RegionCommands extends RegionCommandsBase {
// We didn't find the flag, so let's print a list of flags that the user
// can use, and do nothing afterwards
if (foundFlag == null) {
ArrayList<String> flagList = new ArrayList<>();
// Need to build a list
for (Flag<?> flag : flagRegistry) {
// Can the user set this flag?
if (!permModel.maySetFlag(existing, flag)) {
continue;
}
flagList.add(flag.getName());
}
Collections.sort(flagList);
final TextComponent.Builder builder = TextComponent.builder("Available flags: ");
final HoverEvent clickToSet = HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set"));
for (int i = 0; i < flagList.size(); i++) {
String flag = flagList.get(i);
builder.append(TextComponent.of(flag, i % 2 == 0 ? TextColor.GRAY : TextColor.WHITE)
.hoverEvent(clickToSet).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w " + world.getName() + " " + existing.getId() + " " + flag + " ")));
if (i < flagList.size() + 1) {
builder.append(TextComponent.of(", "));
}
}
sender.printError("Unknown flag specified: " + flagName);
sender.print(builder.build());
if (sender.isPlayer()) {
sender.print(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/rg flags " + existing.getId(), TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg flags -w " + world.getName() + " " + existing.getId()))));
}
AsyncCommandBuilder.wrap(new FlagListBuilder(flagRegistry, permModel, existing, world,
id, sender, flagName), sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), "Flag list for invalid flag command.")
.onSuccess((Component) null, sender::print)
.onFailure((Component) null, WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
return;
} else if (value != null) {
if (foundFlag == Flags.BUILD || foundFlag == Flags.BLOCK_BREAK || foundFlag == Flags.BLOCK_PLACE) {
sender.print(TextComponent.empty().append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" Setting the " + foundFlag.getName() + " flag is not required for protection."))
.append(TextComponent.newline())
.append(TextComponent.of("Setting this flag will completely override default protection, and apply" +
" to members, non-members, pistons, and everything else that can modify blocks."))
.append(TextComponent.newline())
.append(TextComponent.of("Only set this flag if you are sure you know what you are doing. See ")
.append(TextComponent.of("[this documentation page]", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.OPEN_URL,
"https://worldguard.readthedocs.io/en/latest/regions/flags/#protection-related")))
.append(TextComponent.of(" for more info."))));
sender.print(buildFlagWarning);
if (!sender.isPlayer()) {
sender.printRaw("https://worldguard.readthedocs.io/en/latest/regions/flags/#protection-related");
sender.printRaw("https://worldguard.enginehub.org/en/latest/regions/flags/#protection-related");
}
} else if (foundFlag == Flags.PASSTHROUGH) {
sender.print(TextComponent.empty().append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" This flag is unrelated to moving through regions."))
.append(TextComponent.newline())
.append(TextComponent.of("It overrides build checks. If you're unsure what this means, see ")
.append(TextComponent.of("[this documentation page]", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.OPEN_URL,
"https://worldguard.readthedocs.io/en/latest/regions/flags/#overrides")))
.append(TextComponent.of(" for more info."))));
sender.print(passthroughFlagWarning);
if (!sender.isPlayer()) {
sender.printRaw("https://worldguard.readthedocs.io/en/latest/regions/flags/#overrides");
sender.printRaw("https://worldguard.enginehub.org/en/latest/regions/flags/#overrides");
}
}
}
@@ -590,13 +575,14 @@ public final class RegionCommands extends RegionCommandsBase {
if (value != null) {
// Set the flag if [value] was given even if [-g group] was given as well
try {
setFlag(existing, foundFlag, sender, value);
value = setFlag(existing, foundFlag, sender, value).toString();
} catch (InvalidFlagFormat e) {
throw new CommandException(e.getMessage());
}
if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " set on '" + existing.getId() + "' to '" + value + "'.");
String friendlyName = id.getDisplayName(sender);
sender.print("Region flag " + foundFlag.getName() + " set on '" + friendlyName + "' to '" + value + "'.");
}
// No value? Clear the flag, if -g isn't specified
@@ -611,7 +597,8 @@ public final class RegionCommands extends RegionCommandsBase {
}
if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " removed from '" + existing.getId() + "'. (Any -g(roups) were also removed.)");
String friendlyName = id.getDisplayName(sender);
sender.print("Region flag " + foundFlag.getName() + " removed from '" + friendlyName + "'. (Any -g(roups) were also removed.)");
}
}
@@ -647,7 +634,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "p:w:",
desc = "View region flags",
min = 0, max = 2)
public void flagHelper(CommandContext args, Actor sender) throws CommandException {
public void flagHelper(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
World world = checkWorld(args, sender, 'w'); // Get the world
// Lookup the existing region
@@ -659,9 +646,10 @@ public final class RegionCommands extends RegionCommandsBase {
}
region = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg flags -w " + world.getName() + " %id%");
"/rg flags -w \"" + world.getName() + "\" %id%");
} else { // Get region from the ID
region = checkExistingRegion(manager, args.getString(0), true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
region = checkExistingRegion(sender, manager, id);
}
final RegionPermissionModel perms = getPermissionModel(sender);
@@ -676,6 +664,9 @@ public final class RegionCommands extends RegionCommandsBase {
private static void sendFlagHelper(Actor sender, World world, ProtectedRegion region, RegionPermissionModel perms, int page) {
final FlagHelperBox flagHelperBox = new FlagHelperBox(world, region, perms);
flagHelperBox.setComponentsPerPage(18);
if (!sender.isPlayer()) {
flagHelperBox.tryMonoSpacing();
}
AsyncCommandBuilder.wrap(() -> flagHelperBox.create(page), sender)
.onSuccess((Component) null, sender::print)
.onFailure("Failed to get region flags", WorldGuard.getInstance().getExceptionConverter())
@@ -694,7 +685,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "w:",
desc = "Set the priority of a region",
min = 2, max = 2)
public void setPriority(CommandContext args, Actor sender) throws CommandException {
public void setPriority(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -702,7 +693,8 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), false);
RegionIdentifier id = processRegionId(sender, args.getString(0), false);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions
if (!getPermissionModel(sender).maySetPriority(existing)) {
@@ -711,7 +703,8 @@ public final class RegionCommands extends RegionCommandsBase {
existing.setPriority(priority);
sender.print("Priority of '" + existing.getId() + "' set to " + priority + " (higher numbers override).");
String friendlyName = id.getDisplayName(sender);
sender.print("Priority of '" + friendlyName + "' set to " + priority + " (higher numbers override).");
}
/**
@@ -726,7 +719,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "w:",
desc = "Set the parent of a region",
min = 1, max = 2)
public void setParent(CommandContext args, Actor sender) throws CommandException {
public void setParent(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -737,9 +730,11 @@ public final class RegionCommands extends RegionCommandsBase {
RegionManager manager = checkRegionManager(world);
// Get parent and child
child = checkExistingRegion(manager, args.getString(0), false);
RegionIdentifier childId = processRegionId(sender, args.getString(0), false);
child = checkExistingRegion(sender, manager, childId);
if (args.argsLength() == 2) {
parent = checkExistingRegion(manager, args.getString(1), false);
RegionIdentifier parentId = processRegionId(sender, args.getString(1), false);
parent = checkExistingRegion(sender, manager, parentId);
} else {
parent = null;
}
@@ -753,11 +748,15 @@ public final class RegionCommands extends RegionCommandsBase {
child.setParent(parent);
} catch (CircularInheritanceException e) {
// Tell the user what's wrong
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), parent, null, sender);
assert parent != null;
printout.append(ErrorFormat.wrap("Uh oh! Setting '", parent.getId(), "' to be the parent of '", child.getId(),
String parentFriendlyName = parent.getIdentifier().getDisplayName(sender);
String childFriendlyName = childId.getDisplayName(sender);
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), parent, null, sender);
printout.append(ErrorFormat.wrap("Uh oh! Setting '", parentFriendlyName, "' to be the parent of '", childFriendlyName,
"' would cause circular inheritance.")).newline();
printout.append(SubtleFormat.wrap("(Current inheritance on '", parent.getId(), "':")).newline();
printout.append(SubtleFormat.wrap("(Current inheritance on '", parentFriendlyName, "':")).newline();
printout.appendParentTree(true);
printout.append(SubtleFormat.wrap(")"));
printout.send(sender);
@@ -765,8 +764,9 @@ public final class RegionCommands extends RegionCommandsBase {
}
// Tell the user the current inheritance
String childFriendlyName = childId.getDisplayName(sender);
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), child, null, sender);
printout.append(LabelFormat.wrap("Inheritance set for region '", child.getId(), "'."));
printout.append(TextComponent.of("Inheritance set for region '" + childFriendlyName + "'.", TextColor.LIGHT_PURPLE));
if (parent != null) {
printout.newline();
printout.append(SubtleFormat.wrap("(Current inheritance:")).newline();
@@ -790,7 +790,7 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "fuw:",
desc = "Remove a region",
min = 1, max = 1)
public void remove(CommandContext args, Actor sender) throws CommandException {
public void remove(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
warnAboutSaveFailures(sender);
World world = checkWorld(args, sender, 'w'); // Get the world
@@ -799,7 +799,8 @@ public final class RegionCommands extends RegionCommandsBase {
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(manager, args.getString(0), true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, manager, id);
// Check permissions
if (!getPermissionModel(sender).mayDelete(existing)) {
@@ -816,12 +817,15 @@ public final class RegionCommands extends RegionCommandsBase {
task.setRemovalStrategy(RemovalStrategy.UNSET_PARENT_IN_CHILDREN);
}
final String description = String.format("Removing region '%s' in '%s'", existing.getId(), world.getName());
String friendlyName = id.getDisplayName(sender);
final String description = String.format("Removing region '%s' in '%s'", friendlyName, world.getName());
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(WorldGuard.getInstance().getSupervisor(), description)
.sendMessageAfterDelay("Please wait... removing region.")
.onSuccess((Component) null, removed -> sender.print(TextComponent.of(
"Successfully removed " + removed.stream().map(ProtectedRegion::getId).collect(Collectors.joining(", ")) + ".",
"Successfully removed " + removed.stream()
.map((r) -> r.getIdentifier().getDisplayName(sender))
.collect(Collectors.joining(", ")) + ".",
TextColor.LIGHT_PURPLE)))
.onFailure("Failed to remove region", WorldGuard.getInstance().getExceptionConverter())
.buildAndExec(WorldGuard.getInstance().getExecutorService());
@@ -856,10 +860,6 @@ public final class RegionCommands extends RegionCommandsBase {
if (world != null) {
RegionManager manager = checkRegionManager(world);
if (manager == null) {
throw new CommandException("No region manager exists for world '" + world.getName() + "'.");
}
final String description = String.format("Loading region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerLoader(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
@@ -916,10 +916,6 @@ public final class RegionCommands extends RegionCommandsBase {
if (world != null) {
RegionManager manager = checkRegionManager(world);
if (manager == null) {
throw new CommandException("No region manager exists for world '" + world.getName() + "'.");
}
final String description = String.format("Saving region data for '%s'.", world.getName());
AsyncCommandBuilder.wrap(new RegionManagerSaver(manager), sender)
.registerWithSupervisor(worldGuard.getSupervisor(), description)
@@ -1082,14 +1078,15 @@ public final class RegionCommands extends RegionCommandsBase {
flags = "sw:",
desc = "Teleports you to the location associated with the region.",
min = 1, max = 1)
public void teleport(CommandContext args, Actor sender) throws CommandException {
public void teleport(CommandContext args, Actor sender) throws CommandException, AuthorizationException {
LocalPlayer player = worldGuard.checkPlayer(sender);
Location teleportLocation;
// Lookup the existing region
World world = checkWorld(args, player, 'w');
RegionManager regionManager = checkRegionManager(world);
ProtectedRegion existing = checkExistingRegion(regionManager, args.getString(0), true);
RegionIdentifier id = processRegionId(sender, args.getString(0), true);
ProtectedRegion existing = checkExistingRegion(sender, regionManager, id);
// Check permissions
if (!getPermissionModel(player).mayTeleportTo(existing)) {
@@ -1112,7 +1109,90 @@ public final class RegionCommands extends RegionCommandsBase {
}
}
player.setLocation(teleportLocation);
sender.print("Teleported you to the region '" + existing.getId() + "'.");
String friendlyName = id.getDisplayName(sender);
player.teleport(teleportLocation,
"Teleported you to the region '" + friendlyName + "'.",
"Unable to teleport to region '" + friendlyName + "'.");
}
@Command(aliases = {"toggle-bypass", "bypass"},
desc = "Toggle region bypassing, effectively ignoring bypass permissions.")
@CommandPermissions({"worldguard.region.toggle-bypass"})
public void toggleBypass(CommandContext args, Actor sender) throws CommandException {
LocalPlayer player = worldGuard.checkPlayer(sender);
Session session = WorldGuard.getInstance().getPlatform().getSessionManager().get(player);
if (session.hasBypassDisabled()) {
session.setBypassDisabled(false);
player.print("You are now bypassing region protection (as long as you have permission).");
} else {
session.setBypassDisabled(true);
player.print("You are no longer bypassing region protection.");
}
}
private static class FlagListBuilder implements Callable<Component> {
private final FlagRegistry flagRegistry;
private final RegionPermissionModel permModel;
private final ProtectedRegion existing;
private final World world;
private final RegionIdentifier regionId;
private final Actor sender;
private final String flagName;
FlagListBuilder(FlagRegistry flagRegistry, RegionPermissionModel permModel, ProtectedRegion existing,
World world, RegionIdentifier regionId, Actor sender, String flagName) {
this.flagRegistry = flagRegistry;
this.permModel = permModel;
this.existing = existing;
this.world = world;
this.regionId = regionId;
this.sender = sender;
this.flagName = flagName;
}
@Override
public Component call() {
ArrayList<String> flagList = new ArrayList<>();
// Need to build a list
for (Flag<?> flag : flagRegistry) {
// Can the user set this flag?
if (!permModel.maySetFlag(existing, flag)) {
continue;
}
flagList.add(flag.getName());
}
Collections.sort(flagList);
final TextComponent.Builder builder = TextComponent.builder("Available flags: ");
final HoverEvent clickToSet = HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set"));
for (int i = 0; i < flagList.size(); i++) {
String flag = flagList.get(i);
String qualifiedName = regionId.getQualifiedName();
builder.append(TextComponent.of(flag, i % 2 == 0 ? TextColor.GRAY : TextColor.WHITE)
.hoverEvent(clickToSet).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w \"" + world.getName() + "\" " + qualifiedName + " " + flag + " ")));
if (i < flagList.size() + 1) {
builder.append(TextComponent.of(", "));
}
}
Component ret = ErrorFormat.wrap("Unknown flag specified: " + flagName)
.append(TextComponent.newline())
.append(builder.build());
if (sender.isPlayer()) {
String friendlyName = regionId.getDisplayName(sender);
String qualifiedName = regionId.getQualifiedName();
return ret.append(TextComponent.of("Or use the command ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/rg flags " + friendlyName, TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg flags -w \"" + world.getName() + "\" " + qualifiedName))));
}
return ret;
}
}
}
@@ -20,6 +20,7 @@
package com.sk89q.worldguard.commands.region;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.IncompleteRegionException;
@@ -32,6 +33,8 @@ import com.sk89q.worldedit.regions.Polygonal2DRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
@@ -46,13 +49,13 @@ import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.flags.InvalidFlagFormat;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.regions.*;
import com.sk89q.worldguard.util.profile.Profile;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
class RegionCommandsBase {
@@ -74,9 +77,9 @@ class RegionCommandsBase {
* Gets the world from the given flag, or falling back to the the current player
* if the sender is a player, otherwise reporting an error.
*
* @param args the arguments
* @param args the arguments
* @param sender the sender
* @param flag the flag (such as 'w')
* @param flag the flag (such as 'w')
* @return a world
* @throws CommandException on error
*/
@@ -92,28 +95,190 @@ class RegionCommandsBase {
}
}
/**
* Validate a region name.
*
* @param name the name
* @param allowGlobal whether __global__ is allowed
* @throws CommandException thrown on an error
*/
protected static void checkName(String name, boolean allowGlobal) throws CommandException {
if (!RegionIdentifier.isValidName(name)) {
throw new CommandException(
"The region name of '" + name + "' contains characters that are not allowed.");
}
if (!allowGlobal && name.equalsIgnoreCase("__global__")) { // Sorry, no global
throw new CommandException(
"Sorry, you can't use __global__ here.");
}
}
/**
* Validate a region ID.
*
* @param id the id
* @param id the id
* @param allowGlobal whether __global__ is allowed
* @return the id given
* @throws CommandException thrown on an error
*/
@Deprecated
protected static String checkRegionId(String id, boolean allowGlobal) throws CommandException {
if (!ProtectedRegion.isValidId(id)) {
throw new CommandException(
"The region name of '" + id + "' contains characters that are not allowed.");
}
if (!allowGlobal && id.equalsIgnoreCase("__global__")) { // Sorry, no global
throw new CommandException(
"Sorry, you can't use __global__ here.");
}
checkName(id, allowGlobal);
return id;
}
/**
* Validate a region namespace.
*
* @param namespace the namespace name
* @throws CommandException thrown on an error
*/
protected static void checkNamespace(String namespace) throws CommandException {
if (!RegionIdentifier.isValidNamespace(namespace)) {
throw new CommandException(
"The region namespace of '" + namespace + "' contains characters that are not allowed.");
}
}
/**
* Get the unqualified name from a possibly qualified region identifier.
*
* @param id the unprocessed region identifier
* @return the unqualified name, or an empty string if not present
*/
protected static String getUnqualifiedName(String id) {
int namespaceSeparatorIndex = id.lastIndexOf(':');
if (namespaceSeparatorIndex == -1) {
return id;
}
int unqualifiedNameStartIndex = namespaceSeparatorIndex + 1;
if (unqualifiedNameStartIndex == id.length()) {
return "";
}
return id.substring(unqualifiedNameStartIndex);
}
/**
* Get the namespace name from a possibly qualified region identifier.
*
* @param id the unprocessed region identifier
* @return an optional containing the namespace name, or an empty string if qualified,
* if not qualified, an empty optional is returned
*/
protected static Optional<String> getNamespace(String id) {
int namespaceSeparatorIndex = id.lastIndexOf(':');
if (namespaceSeparatorIndex == -1) {
return Optional.empty();
}
return Optional.of(id.substring(0, namespaceSeparatorIndex));
}
private static class InvalidMacroException extends RuntimeException {
public InvalidMacroException(String message) {
super(message);
}
}
/***
* Expand macros in the namespace name.
*
* @param namespace the unexpanded namespace name
* @return the expanded namespace name
*/
protected static String expandNamespace(String namespace) {
if (namespace.startsWith("#")) {
String playerName = namespace.substring(1);
try {
Profile profile = WorldGuard.getInstance().getProfileService().findByName(playerName);
if (profile != null) {
return profile.getUniqueId().toString();
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
throw new InvalidMacroException("Macro unresolvable: " + namespace);
}
return namespace;
}
/**
* Get the macro expanded namespace name from a possibly qualified region identifier.
*
* @param id the unprocessed region identifier
* @return an optional containing the expanded namespace name, or an empty string if qualified,
* if not qualified, an empty optional is returned
*/
protected static Optional<String> getExpandedNamespace(String id) throws CommandException {
try {
return getNamespace(id).map(RegionCommandsBase::expandNamespace);
} catch (InvalidMacroException ex) {
throw new CommandException(ex.getMessage());
}
}
/**
* Get the default namespace for a given actor.
*
* @param sender the sender who's default namespace we intend to retrieve.
* @return the default namespace
*/
protected static String getDefaultNamespace(Actor sender) {
if (sender instanceof LocalPlayer) {
return ((LocalPlayer) sender).getDefaultNamespace();
}
return null;
}
/**
* Process a possibly qualified region identifier into a RegionIdentifier.
*
* This method takes a possibly qualified region identifier, and processes it, expanding any namespace macros,
* running permissions checks, and validating the names for invalid character.
*
* @param sender the contextual sender to use for checks and macro expansions
* @param id the possibly unqualified id
* @param allowGlobal whether or not this method should allow use of the name __global__ name
* @return the processed region id
* @throws AuthorizationException if a permission check fails
* @throws CommandException if a name validation check fails
*/
protected static RegionIdentifier processRegionId(Actor sender, String id, boolean allowGlobal) throws AuthorizationException, CommandException {
String unqualifiedName = getUnqualifiedName(id);
checkName(unqualifiedName, allowGlobal);
Optional<String> optProvidedNamespace = getExpandedNamespace(id);
String namespace = optProvidedNamespace.orElse(getDefaultNamespace(sender));
// TODO use more informative permission checks
// This needs checked as a special case, before namespace name validation.
if (namespace.equals("")) {
sender.checkPermission("worldguard.region.namespace.global");
return new RegionIdentifier(null, unqualifiedName);
}
checkNamespace(namespace);
try {
UUID namespacePlayerId = UUID.fromString(namespace);
if (!namespacePlayerId.equals(sender.getUniqueId())) {
sender.checkPermission("worldguard.region.namespace.player");
}
} catch (IllegalArgumentException ex) {
sender.checkPermission("worldguard.region.namespace.custom." + namespace);
}
return new RegionIdentifier(namespace, unqualifiedName);
}
/**
* Get a protected region by a given name, otherwise throw a
* {@link CommandException}.
@@ -125,6 +290,7 @@ class RegionCommandsBase {
* @param allowGlobal true to allow selecting __global__
* @throws CommandException thrown if no region is found by the given name
*/
@Deprecated
protected static ProtectedRegion checkExistingRegion(RegionManager regionManager, String id, boolean allowGlobal) throws CommandException {
// Validate the id
checkRegionId(id, allowGlobal);
@@ -147,6 +313,36 @@ class RegionCommandsBase {
return region;
}
/**
* Get a protected region by a given name, otherwise throw a
* {@link CommandException}.
*
* <p>This also validates the region ID.</p>
*
* @param actor the associated player
* @param regionManager the region manager
* @param id the name to search
* @throws CommandException thrown if no region is found by the given name
*/
protected static ProtectedRegion checkExistingRegion(Actor actor, RegionManager regionManager, RegionIdentifier id) throws CommandException {
ProtectedRegion region = regionManager.getRegion(id);
// No region found!
if (region == null) {
// But we want a __global__, so let's create one
if (id.getQualifiedName().equals(":__global__")) {
region = new GlobalProtectedRegion(id);
regionManager.addRegion(region);
return region;
}
throw new CommandException(
"No region could be found with the name of '" + id.getDisplayName(actor) + "'.");
}
return region;
}
/**
* Get the region at the player's location, if possible.
@@ -201,10 +397,12 @@ class RegionCommandsBase {
builder.append(TextComponent.of(", "));
}
first = false;
TextComponent regionComp = TextComponent.of(region.getId(), TextColor.AQUA);
RegionIdentifier id = region.getIdentifier();
TextComponent regionComp = TextComponent.of(id.getDisplayName(player), TextColor.AQUA);
if (rgCmd != null && rgCmd.contains("%id%")) {
regionComp = regionComp.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to pick this region")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, rgCmd.replace("%id%", region.getId())));
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, rgCmd.replace("%id%", id.getQualifiedName())));
}
builder.append(regionComp);
}
@@ -230,7 +428,7 @@ class RegionCommandsBase {
throw new CommandException(
"Please select an area first. " +
"Use WorldEdit to make a selection! " +
"(wiki: http://wiki.sk89q.com/wiki/WorldEdit).");
"(see: https://worldedit.enginehub.org/en/latest/usage/regions/selections/).");
}
}
@@ -241,10 +439,23 @@ class RegionCommandsBase {
* @param id the ID
* @throws CommandException thrown if the ID already exists
*/
@Deprecated
protected static void checkRegionDoesNotExist(RegionManager manager, String id, boolean mayRedefine) throws CommandException {
checkRegionDoesNotExist(null, manager, new RegionIdentifier(id), mayRedefine);
}
/**
* Check that a region with the given ID does not already exist.
*
* @param actor the associated player
* @param manager the manager
* @param id the identifier
* @throws CommandException thrown if the ID already exists
*/
protected static void checkRegionDoesNotExist(Actor actor, RegionManager manager, RegionIdentifier id, boolean mayRedefine) throws CommandException {
if (manager.hasRegion(id)) {
throw new CommandException("A region with that name already exists. Please choose another name." +
(mayRedefine ? " To change the shape, use /region redefine " + id + "." : ""));
(mayRedefine ? " To change the shape, use /region redefine " + id.getDisplayName(actor) + "." : ""));
}
}
@@ -254,7 +465,7 @@ class RegionCommandsBase {
* @param world the world
* @throws CommandException thrown if the manager is null
*/
protected static RegionManager checkRegionManager(com.sk89q.worldedit.world.World world) throws CommandException {
protected static RegionManager checkRegionManager(World world) throws CommandException {
if (!WorldGuard.getInstance().getPlatform().getGlobalStateManager().get(world).useRegions) {
throw new CommandException("Region support is disabled in the target world. " +
"It can be enabled per-world in WorldGuard's configuration files. " +
@@ -277,7 +488,20 @@ class RegionCommandsBase {
* @return a new region
* @throws CommandException thrown on an error
*/
@Deprecated
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, String id) throws CommandException {
return checkRegionFromSelection(player, new RegionIdentifier(id));
}
/**
* Create a {@link ProtectedRegion} from the player's selection.
*
* @param player the player
* @param id the identifier of the new region
* @return a new region
* @throws CommandException thrown on an error
*/
protected static ProtectedRegion checkRegionFromSelection(LocalPlayer player, RegionIdentifier id) throws CommandException {
Region selection = checkSelection(player);
// Detect the type of region from WorldEdit
@@ -334,13 +558,31 @@ class RegionCommandsBase {
* @param region the region
*/
protected static void informNewUser(Actor sender, RegionManager manager, ProtectedRegion region) {
if (manager.getRegions().size() <= 2) {
if (manager.size() <= 2) {
sender.print(SubtleFormat.wrap("(This region is NOW PROTECTED from modification from others. Don't want that? Use ")
.append(TextComponent.of("/rg flag " + region.getId() + " passthrough allow", TextColor.AQUA))
.append(TextComponent.of(")", TextColor.GRAY)));
}
}
/**
* Inform a user if the region overlaps spawn protection.
*
* @param sender the sender to send the message to
* @param world the world the region is in
* @param region the region
*/
protected static void checkSpawnOverlap(Actor sender, World world, ProtectedRegion region) {
ProtectedRegion spawn = WorldGuard.getInstance().getPlatform().getSpawnProtection(world);
if (spawn != null) {
if (!spawn.getIntersectingRegions(ImmutableList.of(region)).isEmpty()) {
sender.print(ErrorFormat.wrap("Warning!")
.append(TextComponent.of(" This region overlaps vanilla's spawn protection. WorldGuard cannot " +
"override this, and only server operators will be able to interact with this area.")));
}
}
}
/**
* Set a player's selection to a given region.
*
@@ -392,8 +634,10 @@ class RegionCommandsBase {
* @param value the value
* @throws InvalidFlagFormat thrown if the value is invalid
*/
protected static <V> void setFlag(ProtectedRegion region, Flag<V> flag, Actor sender, String value) throws InvalidFlagFormat {
region.setFlag(flag, flag.parseInput(FlagContext.create().setSender(sender).setInput(value).setObject("region", region).build()));
protected static <V> V setFlag(ProtectedRegion region, Flag<V> flag, Actor sender, String value) throws InvalidFlagFormat {
V val = flag.parseInput(FlagContext.create().setSender(sender).setInput(value).setObject("region", region).build());
region.setFlag(flag, val);
return val;
}
}
@@ -19,7 +19,8 @@
package com.sk89q.worldguard.commands.region;
import com.sk89q.squirrelid.cache.ProfileCache;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
@@ -58,6 +59,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
@Nullable
private final ProfileCache cache;
private final TextComponentProducer builder = new TextComponentProducer();
private final Actor actor;
private final RegionPermissionModel perms;
/**
@@ -70,6 +72,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
this.world = world;
this.region = region;
this.cache = cache;
this.actor = actor;
this.perms = actor != null && actor.isPlayer() ? new RegionPermissionModel(actor) : null;
}
@@ -85,8 +88,10 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
*/
public void appendBasics() {
builder.append(TextComponent.of("Region: ", TextColor.BLUE));
builder.append(TextComponent.of(region.getId(), TextColor.YELLOW)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w " + world + " " + region.getId())));
RegionIdentifier id = region.getIdentifier();
builder.append(TextComponent.of(id.getDisplayName(actor), TextColor.YELLOW)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w \"" + world + "\" " + id.getQualifiedName())));
builder.append(TextComponent.of(" (type=", TextColor.GRAY));
builder.append(TextComponent.of(region.getType().getName()));
@@ -148,7 +153,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
if (perms != null && perms.maySetFlag(region, flag)) {
flagText = flagText.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set flag")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg flag -w " + world + " " + region.getId() + " " + flag.getName() + " "));
"/rg flag -w \"" + world + "\" " + region.getId() + " " + flag.getName() + " "));
}
builder.append(flagText);
@@ -164,7 +169,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
builder.append(TextComponent.space())
.append(TextComponent.of("[Flags]", useColors ? TextColor.GREEN : TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set a flag")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg flags -w " + world + " " + region.getId())));
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg flags -w \"" + world + "\" " + region.getId())));
}
}
@@ -217,7 +222,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
if (perms != null && perms.mayLookup(cur)) {
builder.append(TextComponent.of(cur.getId(), useColors ? TextColor.GREEN : TextColor.WHITE)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click for info")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w " + world + " " + cur.getId())));
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/rg info -w \"" + world + "\" " + cur.getId())));
} else {
builder.append(TextComponent.of(cur.getId(), useColors ? TextColor.GREEN : TextColor.WHITE));
}
@@ -232,7 +237,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
builder.append(TextComponent.space());
builder.append(TextComponent.of("[X]", TextColor.RED)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to unlink parent")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/rg setparent -w " + world + " " + cur.getId())));
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/rg setparent -w \"" + world + "\" " + cur.getId())));
}
last = cur;
@@ -272,17 +277,17 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
builder.append(TextComponent.space().append(TextComponent.of("[Add]", TextColor.GREEN)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to add a player or group")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg " + addCommand + " -w " + world + " " + region.getId() + " "))));
"/rg " + addCommand + " -w \"" + world + "\" " + region.getId() + " "))));
}
if (removeCommand != null && domain.size() > 0) {
builder.append(TextComponent.space().append(TextComponent.of("[Rem]", TextColor.RED)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to remove a player or group")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg " + removeCommand + " -w " + world + " " + region.getId() + " "))));
"/rg " + removeCommand + " -w \"" + world + "\" " + region.getId() + " "))));
builder.append(TextComponent.space().append(TextComponent.of("[Clr]", TextColor.RED)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to clear")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND,
"/rg " + removeCommand + " -w " + world + " -a " + region.getId()))));
"/rg " + removeCommand + " -w \"" + world + "\" -a " + region.getId()))));
}
}
@@ -293,8 +298,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
builder.append(TextComponent.of("Bounds:", TextColor.BLUE));
TextComponent bound = TextComponent.of(" (" + min.getBlockX() + "," + min.getBlockY() + "," + min.getBlockZ() + ")"
+ " -> (" + max.getBlockX() + "," + max.getBlockY() + "," + max.getBlockZ() + ")", TextColor.YELLOW);
TextComponent bound = TextComponent.of(" " + min + " -> " + max, TextColor.YELLOW);
if (perms != null && perms.maySelect(region)) {
bound = bound
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select")))
@@ -302,7 +306,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
}
builder.append(bound);
final Location teleFlag = region.getFlag(Flags.TELE_LOC);
if (perms != null && perms.mayTeleportTo(region) && teleFlag != null) {
if (teleFlag != null && perms != null && perms.mayTeleportTo(region)) {
builder.append(TextComponent.space().append(TextComponent.of("[Teleport]", TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("Click to teleport").append(TextComponent.newline()).append(
@@ -310,7 +314,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
+ teleFlag.getBlockY() + ", "
+ teleFlag.getBlockZ()))))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg tp -w " + world + " " + region.getId()))));
"/rg tp -w \"" + world + "\" " + region.getId()))));
}
newline();
@@ -321,7 +325,7 @@ public class RegionPrintoutBuilder implements Callable<TextComponent> {
if (perms != null && perms.maySetPriority(rg)) {
builder.append(TextComponent.of(content, TextColor.GOLD)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to change")))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/rg setpriority -w " + world + " " + rg.getId() + " ")));
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/rg setpriority -w \"" + world + "\" " + rg.getId() + " ")));
} else {
builder.append(TextComponent.of(content, TextColor.WHITE));
}
@@ -22,7 +22,7 @@ package com.sk89q.worldguard.commands.task;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.squirrelid.Profile;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.text.Component;
@@ -176,7 +176,7 @@ public class RegionLister implements Callable<Integer> {
RegionPermissionModel perms = sender.isPlayer() ? new RegionPermissionModel(sender) : null;
String title = ownerMatcher == null ? "Regions" : "Regions for " + ownerMatcher.getName();
String cmd = "/rg list -w " + world
String cmd = "/rg list -w \"" + world + "\""
+ (playerName != null ? " -p " + playerName : "")
+ (nameOnly ? " -n" : "")
+ " %page%";
@@ -259,13 +259,13 @@ public class RegionLister implements Callable<Integer> {
builder.append(TextComponent.space().append(TextComponent.of("[Info]", TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click for info")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg info -w " + world + " " + entry.region.getId()))));
"/rg info -w \"" + world + "\" " + entry.region.getId()))));
}
if (perms != null && entry.region.getFlag(Flags.TELE_LOC) != null && perms.mayTeleportTo(entry.region)) {
builder.append(TextComponent.space().append(TextComponent.of("[TP]", TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to teleport")))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND,
"/rg tp -w " + world + " " + entry.region.getId()))));
"/rg tp -w \"" + world + "\" " + entry.region.getId()))));
}
return builder.build();
}
@@ -76,6 +76,7 @@ public abstract class ConfigurationManager {
public boolean migrateRegionsToUuid;
public boolean keepUnresolvedNames;
public boolean particleEffects;
public boolean useNamespaces;
@Unreported public Map<String, String> hostKeys = new HashMap<>();
public boolean hostKeysAllowFMLClients;
@@ -19,15 +19,21 @@
package com.sk89q.worldguard.config;
import com.sk89q.worldedit.util.report.Unreported;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.blacklist.Blacklist;
import com.sk89q.worldedit.util.report.Unreported;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -55,7 +61,8 @@ public abstract class WorldConfiguration {
protected File blacklistFile;
@Unreported protected Blacklist blacklist;
@Unreported
protected Blacklist blacklist;
public boolean boundedLocationFlags;
public boolean useRegions;
@@ -111,6 +118,7 @@ public abstract class WorldConfiguration {
public boolean teleportOnSuffocation;
public boolean disableVoidDamage;
public boolean teleportOnVoid;
public boolean safeFallOnVoid;
public boolean disableExplosionDamage;
public boolean disableMobDamage;
public boolean highFreqFlags;
@@ -172,49 +180,63 @@ public abstract class WorldConfiguration {
}
public List<String> convertLegacyItems(List<String> legacyItems) {
return legacyItems.stream().map(this::convertLegacyItem).collect(Collectors.toList());
return legacyItems.stream().map(this::convertLegacyItem).filter(Objects::nonNull).collect(Collectors.toList());
}
public String convertLegacyItem(String legacy) {
String item = legacy;
String[] splitter = legacy.split(":", 2);
try {
String[] splitter = item.split(":", 2);
int id = 0;
byte data = 0;
int id;
byte data;
if (splitter.length == 1) {
id = Integer.parseInt(item);
id = Integer.parseInt(splitter[0]);
data = 0;
} else {
id = Integer.parseInt(splitter[0]);
data = Byte.parseByte(splitter[1]);
}
item = LegacyMapper.getInstance().getItemFromLegacy(id, data).getId();
} catch (Throwable e) {
ItemType legacyItem = LegacyMapper.getInstance().getItemFromLegacy(id, data);
if (legacyItem != null) {
return legacyItem.getId();
}
} catch (NumberFormatException ignored) {
}
final ItemType itemType = ItemTypes.get(legacy);
if (itemType != null) {
return itemType.getId();
}
return item;
return null;
}
public List<String> convertLegacyBlocks(List<String> legacyBlocks) {
return legacyBlocks.stream().map(this::convertLegacyBlock).collect(Collectors.toList());
return legacyBlocks.stream().map(this::convertLegacyBlock).filter(Objects::nonNull).collect(Collectors.toList());
}
public String convertLegacyBlock(String legacy) {
String block = legacy;
String[] splitter = legacy.split(":", 2);
try {
String[] splitter = block.split(":", 2);
int id = 0;
byte data = 0;
int id;
byte data;
if (splitter.length == 1) {
id = Integer.parseInt(block);
id = Integer.parseInt(splitter[0]);
data = 0;
} else {
id = Integer.parseInt(splitter[0]);
data = Byte.parseByte(splitter[1]);
}
block = LegacyMapper.getInstance().getBlockFromLegacy(id, data).getBlockType().getId();
} catch (Throwable e) {
BlockState legacyBlock = LegacyMapper.getInstance().getBlockFromLegacy(id, data);
if (legacyBlock != null) {
return legacyBlock.getBlockType().getId();
}
} catch (NumberFormatException ignored) {
}
final BlockType blockType = BlockTypes.get(legacy);
if (blockType != null) {
return blockType.getId();
}
return block;
return null;
}
public int getMaxRegionCount(LocalPlayer player) {
@@ -63,6 +63,7 @@ public abstract class YamlConfigurationManager extends ConfigurationManager {
usePlayerMove = config.getBoolean("use-player-move-event", true);
usePlayerTeleports = config.getBoolean("use-player-teleports", true);
particleEffects = config.getBoolean("use-particle-effects", true);
useNamespaces = config.getBoolean("use-namespaces", true);
deopOnJoin = config.getBoolean("security.deop-everyone-on-join", false);
blockInGameOp = config.getBoolean("security.block-in-game-op-command", false);
@@ -22,8 +22,8 @@ package com.sk89q.worldguard.domains;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sk89q.squirrelid.Profile;
import com.sk89q.squirrelid.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
@@ -23,8 +23,10 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import javax.annotation.Nullable;
@@ -37,7 +39,13 @@ public class RegionPermissionModel extends AbstractPermissionModel {
super(sender);
}
/**
* @deprecated Check {@code WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass(..)} instead
*/
@Deprecated
public boolean mayIgnoreRegionProtection(World world) {
if (getSender() instanceof LocalPlayer)
return WorldGuard.getInstance().getPlatform().getSessionManager().hasBypass((LocalPlayer) getSender(), world);
return hasPluginPermission("region.bypass." + world.getName());
}
@@ -21,13 +21,18 @@ package com.sk89q.worldguard.internal.platform;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.report.ReportList;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.config.ConfigurationManager;
import com.sk89q.worldguard.protection.flags.FlagContext;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.session.SessionManager;
import com.sk89q.worldguard.util.profile.cache.ProfileCache;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import javax.annotation.Nullable;
import java.nio.file.Path;
/**
@@ -148,4 +153,20 @@ public interface WorldGuardPlatform {
* @param report The reportlist
*/
void addPlatformReports(ReportList report);
/**
* Internal use.
*/
ProfileService createProfileService(ProfileCache profileCache);
/**
* Get a region that encompasses the Vanilla spawn protection for the given world, if applicable.
*
* @param world world to check spawn protection of
* @return a region, or null if not applicable
*/
@Nullable
default ProtectedRegion getSpawnProtection(World world) {
return null;
}
}
@@ -22,7 +22,7 @@ package com.sk89q.worldguard.protection.flags;
/**
* Stores doubles.
*/
public class DoubleFlag extends Flag<Double> {
public class DoubleFlag extends NumberFlag<Double> {
public DoubleFlag(String name, RegionGroup defaultGroup) {
super(name, defaultGroup);
@@ -34,6 +34,7 @@ import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
/**
* The flags that are used in WorldGuard.
@@ -68,6 +69,7 @@ public final class Flags {
public static final StateFlag POTION_SPLASH = register(new StateFlag("potion-splash", false));
public static final StateFlag ITEM_FRAME_ROTATE = register(new StateFlag("item-frame-rotation", false));
public static final StateFlag TRAMPLE_BLOCKS = register(new StateFlag("block-trampling", false));
public static final StateFlag FIREWORK_DAMAGE = register(new StateFlag("firework-damage", false));
// These flags are similar to the ones above (used in tandem with BUILD),
// but their defaults are set to TRUE because it is more user friendly.
@@ -86,11 +88,11 @@ public final class Flags {
public static final StateFlag CREEPER_EXPLOSION = register(new StateFlag("creeper-explosion", true));
public static final StateFlag ENDERDRAGON_BLOCK_DAMAGE = register(new StateFlag("enderdragon-block-damage", true));
public static final StateFlag GHAST_FIREBALL = register(new StateFlag("ghast-fireball", true));
public static final StateFlag FIREWORK_DAMAGE = register(new StateFlag("firework-damage", true));
public static final StateFlag OTHER_EXPLOSION = register(new StateFlag("other-explosion", true));
public static final StateFlag WITHER_DAMAGE = register(new StateFlag("wither-damage", true));
public static final StateFlag ENDER_BUILD = register(new StateFlag("enderman-grief", true));
public static final StateFlag SNOWMAN_TRAILS = register(new StateFlag("snowman-trails", true));
public static final StateFlag RAVAGER_RAVAGE = register(new StateFlag("ravager-grief", true));
public static final StateFlag ENTITY_PAINTING_DESTROY = register(new StateFlag("entity-painting-destroy", true));
public static final StateFlag ENTITY_ITEM_FRAME_DESTROY = register(new StateFlag("entity-item-frame-destroy", true));
@@ -155,15 +157,20 @@ public final class Flags {
public static final RegistryFlag<GameMode> GAME_MODE = register(new RegistryFlag<>("game-mode", GameMode.REGISTRY));
public static final IntegerFlag HEAL_DELAY = register(new IntegerFlag("heal-delay"));
public static final IntegerFlag HEAL_AMOUNT = register(new IntegerFlag("heal-amount"));
public static final DoubleFlag MIN_HEAL = register(new DoubleFlag("heal-min-health"));
public static final DoubleFlag MAX_HEAL = register(new DoubleFlag("heal-max-health"));
private static final Number[] DELAY_VALUES = {0, 1, 5};
private static final Number[] VITALS_VALUES = {0, 5, 10, 20};
private static final Number[] VITALS_MINS = {0, 10};
private static final Number[] VITALS_MAXS = {10, 20};
public static final IntegerFlag FEED_DELAY = register(new IntegerFlag("feed-delay"));
public static final IntegerFlag FEED_AMOUNT = register(new IntegerFlag("feed-amount"));
public static final IntegerFlag MIN_FOOD = register(new IntegerFlag("feed-min-hunger"));
public static final IntegerFlag MAX_FOOD = register(new IntegerFlag("feed-max-hunger"));
public static final IntegerFlag HEAL_DELAY = register(new IntegerFlag("heal-delay"), f -> f.setSuggestedValues(DELAY_VALUES));
public static final IntegerFlag HEAL_AMOUNT = register(new IntegerFlag("heal-amount"), f -> f.setSuggestedValues(VITALS_VALUES));
public static final DoubleFlag MIN_HEAL = register(new DoubleFlag("heal-min-health"), f -> f.setSuggestedValues(VITALS_MINS));
public static final DoubleFlag MAX_HEAL = register(new DoubleFlag("heal-max-health"), f -> f.setSuggestedValues(VITALS_MAXS));
public static final IntegerFlag FEED_DELAY = register(new IntegerFlag("feed-delay"), f -> f.setSuggestedValues(DELAY_VALUES));
public static final IntegerFlag FEED_AMOUNT = register(new IntegerFlag("feed-amount"), f -> f.setSuggestedValues(VITALS_VALUES));
public static final IntegerFlag MIN_FOOD = register(new IntegerFlag("feed-min-hunger"), f -> f.setSuggestedValues(VITALS_MINS));
public static final IntegerFlag MAX_FOOD = register(new IntegerFlag("feed-max-hunger"), f -> f.setSuggestedValues(VITALS_MAXS));
// deny messages
public static final StringFlag DENY_MESSAGE = register(new StringFlag("deny-message",
@@ -188,6 +195,12 @@ public final class Flags {
return flag;
}
private static <T extends Flag<?>> T register(final T flag, Consumer<T> cfg) throws FlagConflictException {
T f = register(flag);
cfg.accept(f);
return f;
}
/**
* Try to match the flag with the given ID using a fuzzy name match.
*
@@ -22,7 +22,7 @@ package com.sk89q.worldguard.protection.flags;
/**
* Stores an integer.
*/
public class IntegerFlag extends Flag<Integer> {
public class IntegerFlag extends NumberFlag<Integer> {
public IntegerFlag(String name, RegionGroup defaultGroup) {
super(name, defaultGroup);
@@ -0,0 +1,47 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores an Number.
*/
public abstract class NumberFlag<T extends Number> extends Flag<T> {
private static final Number[] EMPTY_NUMBER_ARRAY = new Number[0];
private Number[] suggestions = EMPTY_NUMBER_ARRAY;
protected NumberFlag(String name, RegionGroup defaultGroup) {
super(name, defaultGroup);
}
protected NumberFlag(String name) {
super(name);
}
public void setSuggestedValues(Number[] values) {
this.suggestions = checkNotNull(values);
}
public Number[] getSuggestedValues() {
return suggestions;
}
}
@@ -19,6 +19,8 @@
package com.sk89q.worldguard.protection.flags;
import com.sk89q.worldguard.commands.CommandUtils;
import javax.annotation.Nullable;
/**
@@ -56,7 +58,10 @@ public class StringFlag extends Flag<String> {
@Override
public String parseInput(FlagContext context) throws InvalidFlagFormat {
return context.getUserInput().replaceAll("(?!<\\\\)\\\\n", "\n").replaceAll("\\\\\\\\n", "\\n");
String lines = context.getUserInput().replaceAll("(?<!\\\\)\\\\n", "\n").replaceAll("\\\\\\\\n", "\\\\n");
// Add color codes
lines = CommandUtils.replaceColorMacros(lines);
return lines;
}
@Override
@@ -19,6 +19,8 @@
package com.sk89q.worldguard.protection.managers;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.index.ChunkHashTable;
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
@@ -29,15 +31,22 @@ import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Supplier;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Manages different {@link RegionManager}s for different worlds or dimensions.
*
@@ -52,8 +61,8 @@ public class RegionContainerImpl {
private final ConcurrentMap<Normal, RegionManager> mapping = new ConcurrentHashMap<>();
private final Object lock = new Object();
private final RegionDriver driver;
private final Supplier<? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
private final Timer timer = new Timer();
private final Function<String, ? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
private final Timer timer = new Timer("WorldGuard Region I/O");
private final FlagRegistry flagRegistry;
private final Set<Normal> failingLoads = new HashSet<>();
@@ -182,6 +191,14 @@ public class RegionContainerImpl {
}
}
/**
* Disable completely.
*/
public void shutdown() {
timer.cancel();
unloadAll();
}
/**
* Get the region manager for the given world name.
*
@@ -34,9 +34,11 @@ import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionIdentifier;
import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -47,9 +49,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import java.util.function.Function;
/**
* A region manager holds the regions for a world.
@@ -57,7 +57,7 @@ import javax.annotation.Nullable;
public final class RegionManager {
private final RegionDatabase store;
private final Supplier<? extends ConcurrentRegionIndex> indexFactory;
private final Function<String, ? extends ConcurrentRegionIndex> indexFactory;
private final FlagRegistry flagRegistry;
private ConcurrentRegionIndex index;
@@ -68,14 +68,14 @@ public final class RegionManager {
* @param indexFactory the factory for creating new instances of the index
* @param flagRegistry the flag registry
*/
public RegionManager(RegionDatabase store, Supplier<? extends ConcurrentRegionIndex> indexFactory, FlagRegistry flagRegistry) {
public RegionManager(RegionDatabase store, Function<String, ? extends ConcurrentRegionIndex> indexFactory, FlagRegistry flagRegistry) {
checkNotNull(store);
checkNotNull(indexFactory);
checkNotNull(flagRegistry, "flagRegistry");
this.store = store;
this.indexFactory = indexFactory;
this.index = indexFactory.get();
this.index = indexFactory.apply(store.getName());
this.flagRegistry = flagRegistry;
}
@@ -218,7 +218,7 @@ public final class RegionManager {
public void setRegions(Collection<ProtectedRegion> regions) {
checkNotNull(regions);
ConcurrentRegionIndex newIndex = indexFactory.get();
ConcurrentRegionIndex newIndex = indexFactory.apply(getName());
newIndex.addAll(regions);
newIndex.getAndClearDifference(); // Clear changes
this.index = newIndex;
@@ -243,10 +243,22 @@ public final class RegionManager {
* @param id the name of the region
* @return true if this index contains the region
*/
@Deprecated
public boolean hasRegion(String id) {
return index.contains(id);
}
/**
* Return whether the index contains a region with the given identifier,
* with quality determined by {@link Normal}.
*
* @param id the region identifier
* @return true if this index contains the region
*/
public boolean hasRegion(RegionIdentifier id) {
return index.contains(id.getLegacyQualifiedName());
}
/**
* Get the region named by the given name (equality determined using
* {@link Normal}).
@@ -255,11 +267,24 @@ public final class RegionManager {
* @return a region or {@code null}
*/
@Nullable
@Deprecated
public ProtectedRegion getRegion(String id) {
checkNotNull(id);
return index.get(id);
}
/**
* Get the region named y the given id.
*
* @param id the region identifier
* @return a region or {@code null}
*/
@Nullable
public ProtectedRegion getRegion(RegionIdentifier id) {
checkNotNull(id);
return index.get(id.getLegacyQualifiedName());
}
/**
* @deprecated Use exact ids with {@link #getRegion}
*/
@@ -41,8 +41,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.annotation.Nullable;
@@ -52,6 +52,7 @@ import javax.annotation.Nullable;
*/
public class ChunkHashTable implements ConcurrentRegionIndex {
private final String name;
private ListeningExecutorService executor = createExecutor();
private LongHashTable<ChunkState> states = new LongHashTable<>();
private final RegionIndex index;
@@ -63,10 +64,12 @@ public class ChunkHashTable implements ConcurrentRegionIndex {
* Create a new instance.
*
* @param index the index
* @param name
*/
public ChunkHashTable(RegionIndex index) {
public ChunkHashTable(RegionIndex index, String name) {
checkNotNull(index);
this.index = index;
this.name = name;
}
/**
@@ -75,8 +78,8 @@ public class ChunkHashTable implements ConcurrentRegionIndex {
* @return an executor service
*/
private ListeningExecutorService createExecutor() {
return MoreExecutors.listeningDecorator(
EvenMoreExecutors.newBoundedCachedThreadPool(0, 4, Integer.MAX_VALUE));
return MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 4, Integer.MAX_VALUE,
"WorldGuard Region Chunk Table - " + name));
}
/**
@@ -361,17 +364,17 @@ public class ChunkHashTable implements ConcurrentRegionIndex {
/**
* A factory for instances of {@code ChunkHashCache}.
*/
public static class Factory implements Supplier<ChunkHashTable> {
private final Supplier<? extends ConcurrentRegionIndex> supplier;
public static class Factory implements Function<String, ChunkHashTable> {
private final Function<String, ? extends ConcurrentRegionIndex> supplier;
public Factory(Supplier<? extends ConcurrentRegionIndex> supplier) {
public Factory(Function<String, ? extends ConcurrentRegionIndex> supplier) {
checkNotNull(supplier);
this.supplier = supplier;
}
@Override
public ChunkHashTable get() {
return new ChunkHashTable(supplier.get());
public ChunkHashTable apply(String name) {
return new ChunkHashTable(supplier.apply(name), name);
}
}
@@ -28,6 +28,7 @@ import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -35,10 +36,8 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.annotation.Nullable;
/**
* An index that stores regions in a hash map, which allows for fast lookup
@@ -71,12 +70,13 @@ public class HashMapIndex extends AbstractRegionIndex implements ConcurrentRegio
region.setDirty(true);
synchronized (lock) {
String normalId = normalize(region.getId());
String newFullId = region.getIdentifier().getLegacyQualifiedName();
String normalId = normalize(newFullId);
ProtectedRegion existing = regions.get(normalId);
// Casing / form of ID has changed
if (existing != null && !existing.getId().equals(region.getId())) {
if (existing != null && !existing.getIdentifier().getLegacyQualifiedName().equals(newFullId)) {
removed.add(existing);
}
@@ -287,9 +287,9 @@ public class HashMapIndex extends AbstractRegionIndex implements ConcurrentRegio
/**
* A factory for new instances using this index.
*/
public static final class Factory implements Supplier<HashMapIndex> {
public static final class Factory implements Function<String, HashMapIndex> {
@Override
public HashMapIndex get() {
public HashMapIndex apply(String name) {
return new HashMapIndex();
}
}
@@ -30,8 +30,8 @@ import org.khelekore.prtree.SimpleMBR;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* An implementation of an index that uses {@link HashMapIndex} for queries
@@ -103,9 +103,9 @@ public class PriorityRTreeIndex extends HashMapIndex {
/**
* A factory for new instances using this index.
*/
public static final class Factory implements Supplier<PriorityRTreeIndex> {
public static final class Factory implements Function<String, PriorityRTreeIndex> {
@Override
public PriorityRTreeIndex get() {
public PriorityRTreeIndex apply(String name) {
return new PriorityRTreeIndex();
}
}
@@ -20,8 +20,8 @@
package com.sk89q.worldguard.protection.managers.migration;
import com.google.common.base.Predicate;
import com.sk89q.squirrelid.Profile;
import com.sk89q.squirrelid.resolver.ProfileService;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.domains.PlayerDomain;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
@@ -31,7 +31,12 @@ import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.io.IOException;
import java.util.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
@@ -47,7 +52,7 @@ public class UUIDMigration extends AbstractMigration {
private static final Logger log = Logger.getLogger(UUIDMigration.class.getCanonicalName());
private static final int LOG_DELAY = 5000;
private final Timer timer = new Timer();
private final Timer timer = new Timer("WorldGuard UUID Migration");
private final ProfileService profileService;
private final FlagRegistry flagRegistry;
private final ConcurrentMap<String, UUID> resolvedNames = new ConcurrentHashMap<>();
@@ -0,0 +1,60 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.worldguard.domains.DefaultDomain;
import java.util.UUID;
import java.util.logging.Level;
class DomainParser {
public static class One {
public static DefaultDomain parseDomain(YAMLNode node) {
if (node == null) {
return new DefaultDomain();
}
DefaultDomain domain = new DefaultDomain();
for (String name : node.getStringList("players", null)) {
if (!name.isEmpty()) {
domain.addPlayer(name);
}
}
for (String stringId : node.getStringList("unique-ids", null)) {
try {
domain.addPlayer(UUID.fromString(stringId));
} catch (IllegalArgumentException e) {
YamlCommon.log.log(Level.WARNING, "Failed to parse UUID '" + stringId + "'", e);
}
}
for (String name : node.getStringList("groups", null)) {
if (!name.isEmpty()) {
domain.addGroup(name);
}
}
return domain;
}
}
}
@@ -16,3 +16,19 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
class FlagParser {
public static class One {
public static void setFlags(FlagRegistry flagRegistry, ProtectedRegion region, YAMLNode flagsData) {
if (flagsData != null) {
region.setFlags(flagRegistry.unmarshal(flagsData.getMap(), true));
}
}
}
}
@@ -0,0 +1,59 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.managers.storage.file;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.representer.Representer;
import java.util.logging.Logger;
class YamlCommon {
public static final Logger log = Logger.getLogger(YamlRegionFile.class.getCanonicalName());
public static final Yaml ERROR_DUMP_YAML;
static {
DumperOptions options = new DumperOptions();
options.setIndent(4);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.AUTO);
ERROR_DUMP_YAML = new Yaml(new SafeConstructor(), new Representer(), options);
}
public static final String YAML_GLOBAL_NAMESPACE_NAME = "__global_ns__";
private YamlCommon() {
}
/**
* Dump the given object as YAML for debugging purposes.
*
* @param object the object
* @return the YAML string or an error string if dumping fals
*/
public static String toYamlOutput(Object object) {
try {
return ERROR_DUMP_YAML.dump(object).replaceAll("(?m)^", "\t");
} catch (Throwable t) {
return "<error while dumping object>";
}
}
}
@@ -17,19 +17,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.bukkit.listener;
package com.sk89q.worldguard.protection.managers.storage.file;
import com.google.common.base.Function;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Set;
class BlockStateAsBlockFunction implements Function<BlockState, Block> {
@Override
public Block apply(@Nullable BlockState blockState) {
return blockState != null ? blockState.getBlock() : null;
interface YamlReader {
public int getVersion();
default public boolean canLoad(YAMLProcessor config) {
return config.getInt("version", 1) == getVersion();
}
public Set<ProtectedRegion> load(FlagRegistry flagRegistry, YAMLProcessor config);
}
@@ -0,0 +1,114 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.util.*;
import java.util.logging.Level;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.log;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.toYamlOutput;
class YamlReaderVersionOne implements YamlReader {
@Override
public int getVersion() {
return 1;
}
@Override
public Set<ProtectedRegion> load(FlagRegistry flagRegistry, YAMLProcessor config) {
Map<String, ProtectedRegion> loaded = new HashMap<>();
Map<String, YAMLNode> regionData = config.getNodes("regions");
if (regionData == null) {
return Collections.emptySet(); // No regions are even configured
}
Map<ProtectedRegion, String> parentSets = new LinkedHashMap<>();
for (Map.Entry<String, YAMLNode> entry : regionData.entrySet()) {
String id = entry.getKey();
YAMLNode node = entry.getValue();
String type = node.getString("type");
ProtectedRegion region;
try {
if (type == null) {
log.warning("Undefined region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
} else if (type.equals("cuboid")) {
Vector3 pt1 = checkNotNull(node.getVector("min"));
Vector3 pt2 = checkNotNull(node.getVector("max"));
BlockVector3 min = pt1.getMinimum(pt2).toBlockPoint();
BlockVector3 max = pt1.getMaximum(pt2).toBlockPoint();
region = new ProtectedCuboidRegion(id, min, max);
} else if (type.equals("poly2d")) {
Integer minY = checkNotNull(node.getInt("min-y"));
Integer maxY = checkNotNull(node.getInt("max-y"));
List<BlockVector2> points = node.getBlockVector2List("points", null);
region = new ProtectedPolygonalRegion(id, points, minY, maxY);
} else if (type.equals("global")) {
region = new GlobalProtectedRegion(id);
} else {
log.warning("Unknown region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
}
Integer priority = checkNotNull(node.getInt("priority"));
region.setPriority(priority);
FlagParser.One.setFlags(flagRegistry, region, node.getNode("flags"));
region.setOwners(DomainParser.One.parseDomain(node.getNode("owners")));
region.setMembers(DomainParser.One.parseDomain(node.getNode("members")));
loaded.put(id, region);
String parentId = node.getString("parent");
if (parentId != null) {
parentSets.put(region, parentId);
}
} catch (NullPointerException e) {
log.log(Level.WARNING,
"Unexpected NullPointerException encountered during parsing for the region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) +
"\n\nNote: This region will disappear as a result!", e);
}
}
// Relink parents
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<>(loaded.values());
}
}
@@ -0,0 +1,120 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.managers.storage.file;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.regions.*;
import java.util.*;
import java.util.logging.Level;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.*;
class YamlReaderVersionTwo implements YamlReader {
@Override
public int getVersion() {
return 2;
}
@Override
public Set<ProtectedRegion> load(FlagRegistry flagRegistry, YAMLProcessor config) {
Map<String, ProtectedRegion> loaded = new HashMap<>();
Map<String, YAMLNode> regionData = config.getNodes("regions");
if (regionData == null) {
return Collections.emptySet(); // No regions are even configured
}
Map<ProtectedRegion, String> parentSets = new LinkedHashMap<>();
for (Map.Entry<String, YAMLNode> namespaceEntry : regionData.entrySet()) {
String namespaceKey = namespaceEntry.getKey();
String namespace = namespaceKey;
if (namespace.equals(YAML_GLOBAL_NAMESPACE_NAME)) {
namespace = null;
}
for (Map.Entry<String, Object> entry : namespaceEntry.getValue().getMap().entrySet()) {
String name = entry.getKey();
YAMLNode node = config.getNode("regions." + namespaceKey + "." + name);
String type = node.getString("type");
ProtectedRegion region;
RegionIdentifier id = new RegionIdentifier(namespace, name);
try {
if (type == null) {
log.warning("Undefined region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(node.getMap()) + "\n");
continue;
} else if (type.equals("cuboid")) {
Vector3 pt1 = checkNotNull(node.getVector("min"));
Vector3 pt2 = checkNotNull(node.getVector("max"));
BlockVector3 min = pt1.getMinimum(pt2).toBlockPoint();
BlockVector3 max = pt1.getMaximum(pt2).toBlockPoint();
region = new ProtectedCuboidRegion(id, min, max);
} else if (type.equals("poly2d")) {
Integer minY = checkNotNull(node.getInt("min-y"));
Integer maxY = checkNotNull(node.getInt("max-y"));
List<BlockVector2> points = node.getBlockVector2List("points", null);
region = new ProtectedPolygonalRegion(id, points, minY, maxY);
} else if (type.equals("global")) {
region = new GlobalProtectedRegion(id);
} else {
log.warning("Unknown region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(node.getMap()) + "\n");
continue;
}
Integer priority = checkNotNull(node.getInt("priority"));
region.setPriority(priority);
FlagParser.One.setFlags(flagRegistry, region, node.getNode("flags"));
region.setOwners(DomainParser.One.parseDomain(node.getNode("owners")));
region.setMembers(DomainParser.One.parseDomain(node.getNode("members")));
loaded.put(id.getLegacyQualifiedName(), region);
String parentQualifiedName = node.getString("parent");
if (parentQualifiedName != null) {
parentSets.put(region, parentQualifiedName);
}
} catch (NullPointerException e) {
log.log(Level.WARNING,
"Unexpected NullPointerException encountered during parsing for the region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(node.getMap()) +
"\n\nNote: This region will disappear as a result!", e);
}
}
}
// Relink parents
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<>(loaded.values());
}
}
@@ -19,56 +19,32 @@
package com.sk89q.worldguard.protection.managers.storage.file;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.util.yaml.YAMLFormat;
import com.sk89q.util.yaml.YAMLNode;
import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.FlagUtil;
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import com.sk89q.worldguard.protection.regions.*;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.managers.storage.file.YamlCommon.YAML_GLOBAL_NAMESPACE_NAME;
/**
* A store that persists regions in a YAML-encoded file.
*/
public class YamlRegionFile implements RegionDatabase {
private static final Logger log = Logger.getLogger(YamlRegionFile.class.getCanonicalName());
private static final Yaml ERROR_DUMP_YAML;
private static final String FILE_HEADER = "#\r\n" +
"# WorldGuard regions file\r\n" +
"#\r\n" +
@@ -81,17 +57,19 @@ public class YamlRegionFile implements RegionDatabase {
"# REMEMBER TO KEEP PERIODICAL BACKUPS.\r\n" +
"#";
private final String name;
private final File file;
private static final List<YamlReader> YAML_READERS = new ArrayList<>();
static {
DumperOptions options = new DumperOptions();
options.setIndent(4);
options.setDefaultFlowStyle(FlowStyle.AUTO);
ERROR_DUMP_YAML = new Yaml(new SafeConstructor(), new Representer(), options);
// IMPORTANT: For best performance, add these in reverse order.
// We always want the latest version to be attempted first, so that once migrated, we are checking
// one version, not n.
YAML_READERS.add(new YamlReaderVersionTwo());
YAML_READERS.add(new YamlReaderVersionOne());
}
private final String name;
private final File file;
/**
* Create a new instance.
*
@@ -112,80 +90,22 @@ public class YamlRegionFile implements RegionDatabase {
@Override
public Set<ProtectedRegion> loadAll(FlagRegistry flagRegistry) throws StorageException {
Map<String, ProtectedRegion> loaded = new HashMap<>();
YAMLProcessor config = createYamlProcessor(file);
try {
config.load();
} catch (FileNotFoundException e) {
return new HashSet<>(loaded.values());
return new HashSet<>();
} catch (IOException | ParserException e) {
throw new StorageException("Failed to load region data from '" + file + "'", e);
}
Map<String, YAMLNode> regionData = config.getNodes("regions");
if (regionData == null) {
return Collections.emptySet(); // No regions are even configured
}
Map<ProtectedRegion, String> parentSets = new LinkedHashMap<>();
for (Map.Entry<String, YAMLNode> entry : regionData.entrySet()) {
String id = entry.getKey();
YAMLNode node = entry.getValue();
String type = node.getString("type");
ProtectedRegion region;
try {
if (type == null) {
log.warning("Undefined region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
} else if (type.equals("cuboid")) {
Vector3 pt1 = checkNotNull(node.getVector("min"));
Vector3 pt2 = checkNotNull(node.getVector("max"));
BlockVector3 min = pt1.getMinimum(pt2).toBlockPoint();
BlockVector3 max = pt1.getMaximum(pt2).toBlockPoint();
region = new ProtectedCuboidRegion(id, min, max);
} else if (type.equals("poly2d")) {
Integer minY = checkNotNull(node.getInt("min-y"));
Integer maxY = checkNotNull(node.getInt("max-y"));
List<BlockVector2> points = node.getBlockVector2List("points", null);
region = new ProtectedPolygonalRegion(id, points, minY, maxY);
} else if (type.equals("global")) {
region = new GlobalProtectedRegion(id);
} else {
log.warning("Unknown region type for region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) + "\n");
continue;
}
Integer priority = checkNotNull(node.getInt("priority"));
region.setPriority(priority);
setFlags(flagRegistry, region, node.getNode("flags"));
region.setOwners(parseDomain(node.getNode("owners")));
region.setMembers(parseDomain(node.getNode("members")));
loaded.put(id, region);
String parentId = node.getString("parent");
if (parentId != null) {
parentSets.put(region, parentId);
}
} catch (NullPointerException e) {
log.log(Level.WARNING,
"Unexpected NullPointerException encountered during parsing for the region '" + id + "'!\n" +
"Here is what the region data looks like:\n\n" + toYamlOutput(entry.getValue().getMap()) +
"\n\nNote: This region will disappear as a result!", e);
for (YamlReader reader : YAML_READERS) {
if (reader.canLoad(config)) {
return reader.load(flagRegistry, config);
}
}
// Relink parents
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<>(loaded.values());
throw new IllegalStateException("No YAML reader was registered that understands the saved region information");
}
@Override
@@ -197,13 +117,25 @@ public class YamlRegionFile implements RegionDatabase {
config.clear();
config.setProperty("version", YAML_READERS.get(0).getVersion());
YAMLNode regionsNode = config.addNode("regions");
Map<String, Object> map = regionsNode.getMap();
// Creates a mapping of existing namespace node names, to their underlying YAMLNode.
Map<String, YAMLNode> namespaceMap = new HashMap<>();
for (ProtectedRegion region : regions) {
Map<String, Object> nodeMap = new HashMap<>();
map.put(region.getId(), nodeMap);
YAMLNode node = new YAMLNode(nodeMap, false);
RegionIdentifier identifier = region.getIdentifier();
String internalNamespace = identifier.getNamespace().orElse(YAML_GLOBAL_NAMESPACE_NAME);
YAMLNode namespaceNode = namespaceMap.compute(internalNamespace, (ignored, existingNamespaceNode) -> {
if (existingNamespaceNode == null) {
existingNamespaceNode = regionsNode.addNode(internalNamespace);
}
return existingNamespaceNode;
});
YAMLNode node = namespaceNode.addNode(identifier.getName());
if (region instanceof ProtectedCuboidRegion) {
ProtectedCuboidRegion cuboid = (ProtectedCuboidRegion) region;
@@ -238,7 +170,7 @@ public class YamlRegionFile implements RegionDatabase {
ProtectedRegion parent = region.getParent();
if (parent != null) {
node.setProperty("parent", parent.getId());
node.setProperty("parent", parent.getIdentifier().getLegacyQualifiedName());
}
}
@@ -257,46 +189,10 @@ public class YamlRegionFile implements RegionDatabase {
throw new DifferenceSaveException("Not supported");
}
private DefaultDomain parseDomain(YAMLNode node) {
if (node == null) {
return new DefaultDomain();
}
DefaultDomain domain = new DefaultDomain();
for (String name : node.getStringList("players", null)) {
if (!name.isEmpty()) {
domain.addPlayer(name);
}
}
for (String stringId : node.getStringList("unique-ids", null)) {
try {
domain.addPlayer(UUID.fromString(stringId));
} catch (IllegalArgumentException e) {
log.log(Level.WARNING, "Failed to parse UUID '" + stringId + "'", e);
}
}
for (String name : node.getStringList("groups", null)) {
if (!name.isEmpty()) {
domain.addGroup(name);
}
}
return domain;
}
private Map<String, Object> getFlagData(ProtectedRegion region) {
return FlagUtil.marshal(region.getFlags());
}
private void setFlags(FlagRegistry flagRegistry, ProtectedRegion region, YAMLNode flagsData) {
if (flagsData != null) {
region.setFlags(flagRegistry.unmarshal(flagsData.getMap(), true));
}
}
private Map<String, Object> getDomainData(DefaultDomain domain) {
Map<String, Object> domainData = new HashMap<>();
@@ -331,19 +227,4 @@ public class YamlRegionFile implements RegionDatabase {
checkNotNull(file);
return new YAMLProcessor(file, false, YAMLFormat.COMPACT);
}
/**
* Dump the given object as YAML for debugging purposes.
*
* @param object the object
* @return the YAML string or an error string if dumping fals
*/
private static String toYamlOutput(Object object) {
try {
return ERROR_DUMP_YAML.dump(object).replaceAll("(?m)^", "\t");
} catch (Throwable t) {
return "<error while dumping object>";
}
}
}
@@ -44,6 +44,7 @@ public class GlobalProtectedRegion extends ProtectedRegion {
*
* @param id the ID
*/
@Deprecated
public GlobalProtectedRegion(String id) {
this(id, false);
}
@@ -54,7 +55,29 @@ public class GlobalProtectedRegion extends ProtectedRegion {
* @param id the ID
* @param transientRegion whether this region should only be kept in memory and not be saved
*/
@Deprecated
public GlobalProtectedRegion(String id, boolean transientRegion) {
this(new RegionIdentifier(id), transientRegion);
}
/**
* Create a new instance.<br>
* Equivalent to {@link #GlobalProtectedRegion(String, boolean) GlobalProtectedRegion(id, false)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
*/
public GlobalProtectedRegion(RegionIdentifier id) {
this(id, false);
}
/**
* Create a new instance.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
*/
public GlobalProtectedRegion(RegionIdentifier id, boolean transientRegion) {
super(id, transientRegion);
min = BlockVector3.ZERO;
max = BlockVector3.ZERO;
@@ -47,6 +47,7 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
@Deprecated
public ProtectedCuboidRegion(String id, BlockVector3 pt1, BlockVector3 pt2) {
this(id, false, pt1, pt2);
}
@@ -59,7 +60,34 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
@Deprecated
public ProtectedCuboidRegion(String id, boolean transientRegion, BlockVector3 pt1, BlockVector3 pt2) {
this(new RegionIdentifier(id), transientRegion, pt1, pt2);
}
/**
* Construct a new instance of this cuboid region.<br>
* Equivalent to {@link #ProtectedCuboidRegion(RegionIdentifier, boolean, BlockVector3, BlockVector3)
* ProtectedCuboidRegion(id, false, pt1, pt2)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
public ProtectedCuboidRegion(RegionIdentifier id, BlockVector3 pt1, BlockVector3 pt2) {
this(id, false, pt1, pt2);
}
/**
* Construct a new instance of this cuboid region.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
* @param pt1 the first point of this region
* @param pt2 the second point of this region
*/
public ProtectedCuboidRegion(RegionIdentifier id, boolean transientRegion, BlockVector3 pt1, BlockVector3 pt2) {
super(id, transientRegion);
setMinMaxPoints(pt1, pt2);
}
@@ -47,6 +47,7 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
@Deprecated
public ProtectedPolygonalRegion(String id, List<BlockVector2> points, int minY, int maxY) {
this(id, false, points, minY, maxY);
}
@@ -60,7 +61,37 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
@Deprecated
public ProtectedPolygonalRegion(String id, boolean transientRegion, List<BlockVector2> points, int minY, int maxY) {
this(new RegionIdentifier(id), transientRegion, points, minY, maxY);
}
/**
* Construct a new instance of this polygonal region.<br>
* Equivalent to {@link #ProtectedPolygonalRegion(RegionIdentifier, boolean, List, int, int)
* ProtectedPolygonalRegion(id, false, points, minY, maxY)}<br>
* <code>transientRegion</code> will be set to false, and this region can be saved.
*
* @param id the region identifier
* @param points a {@link List} of points that this region should contain
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
public ProtectedPolygonalRegion(RegionIdentifier id, List<BlockVector2> points, int minY, int maxY) {
this(id, false, points, minY, maxY);
}
/**
* Construct a new instance of this polygonal region.
*
* @param id the region identifier
* @param transientRegion whether this region should only be kept in memory and not be saved
* @param points a {@link List} of points that this region should contain
* @param minY the minimum y coordinate
* @param maxY the maximum y coordinate
*/
public ProtectedPolygonalRegion(RegionIdentifier id, boolean transientRegion, List<BlockVector2> points,
int minY, int maxY) {
super(id, transientRegion);
ImmutableList<BlockVector2> immutablePoints = ImmutableList.copyOf(points);
setMinMaxPoints(immutablePoints, minY, maxY);
@@ -28,7 +28,6 @@ import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.util.ChangeTracked;
import com.sk89q.worldguard.util.Normal;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
@@ -37,7 +36,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
@@ -50,12 +48,11 @@ import javax.annotation.Nullable;
public abstract class ProtectedRegion implements ChangeTracked, Comparable<ProtectedRegion> {
public static final String GLOBAL_REGION = "__global__";
private static final Pattern VALID_ID_PATTERN = Pattern.compile("^[A-Za-z0-9_,'\\-\\+/]{1,}$");
protected BlockVector3 min;
protected BlockVector3 max;
private final String id;
private final RegionIdentifier id;
private final boolean transientRegion;
private int priority = 0;
private ProtectedRegion parent;
@@ -67,18 +64,13 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
/**
* Construct a new instance of this region.
*
* @param id the name of this region
* @param id the name information for this region
* @param transientRegion whether this region should only be kept in memory and not be saved
* @throws IllegalArgumentException thrown if the ID is invalid (see {@link #isValidId(String)}
*/
ProtectedRegion(String id, boolean transientRegion) { // Package private because we can't have people creating their own region types
ProtectedRegion(RegionIdentifier id, boolean transientRegion) { // Package private because we can't have people creating their own region types
checkNotNull(id);
if (!isValidId(id)) {
throw new IllegalArgumentException("Invalid region ID: " + id);
}
this.id = Normal.normalize(id);
this.id = id;
this.transientRegion = transientRegion;
}
@@ -119,7 +111,17 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
*
* @return the name
*/
@Deprecated
public String getId() {
return id.getLegacyQualifiedName();
}
/**
* Gets the identifier info for this region.
*
* @return the identifier info
*/
public RegionIdentifier getIdentifier() {
return id;
}
@@ -734,9 +736,9 @@ public abstract class ProtectedRegion implements ChangeTracked, Comparable<Prote
* @param id the id to check
* @return whether the region id given is valid
*/
@Deprecated
public static boolean isValidId(String id) {
checkNotNull(id);
return VALID_ID_PATTERN.matcher(id).matches();
return RegionIdentifier.isValidName(id);
}
/**
@@ -0,0 +1,147 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.regions;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.util.Normal;
import com.sk89q.worldguard.util.profile.Profile;
import javax.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
public final class RegionIdentifier {
private static final Pattern VALID_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_,'\\-\\+/]{1,}$");
private String namespace;
private String name;
/**
* Construct a new RegionIdentifier for describing region name information, using the global namespace.<br>
* Equivalent to {@link #RegionIdentifier(String, String) RegionIdentifier(null, name)}<br>
* <code>namespace</code> will be set to null.
*
* @param name the name for this region
* @throws IllegalArgumentException thrown if the name is invalid (see {@link #isValidName(String)}
*/
public RegionIdentifier(String name) {
this(null, name);
}
/**
* Construct a new RegionIdentifier for describing region name information.
*
* @param namespace the namespace name for this region, or null if there isn't one
* @param name the name for this region
* @throws IllegalArgumentException thrown if the namespace is invalid (see {@link #isValidNamespace(String)}
* @throws IllegalArgumentException thrown if the name is invalid (see {@link #isValidName(String)}
*/
public RegionIdentifier(@Nullable String namespace, String name) {
if (!isValidNamespace(name)) {
throw new IllegalArgumentException("Invalid region namespace: " + namespace);
}
if (!isValidName(name)) {
throw new IllegalArgumentException("Invalid region name: " + name);
}
this.namespace = namespace == null ? null : Normal.normalize(namespace);
this.name = Normal.normalize(name);
}
/**
* Returns the qualified name. This is incompatible with the legacy naming scheme, and
* should be used when interacting with the command system. This will ensure that the correct
* region is referenced regardless of the user's default namespace.
*
* @return the qualified name
*/
public String getQualifiedName() {
return getNamespace().orElse("") + ":" + name;
}
/**
* Returns the legacy qualified name. This is compatible with the legacy naming scheme, and
* should be used when interacting with the region manager via names.
*
* If you're using this outside of WorldGuard internals, you're doing something wrong.
*
* @return the legacy qualified name
*/
@Deprecated
public String getLegacyQualifiedName() {
return getNamespace().map((ns) -> ns + ':' + getName()).orElse(getName());
}
/**
* Compresses the name into a more user friendly macro based name.
*
* @param actor a player context
* @return the user friendly display name
*/
public String getDisplayName(Actor actor) {
if (actor instanceof LocalPlayer) {
LocalPlayer player = (LocalPlayer) actor;
if (player.isDefaultNamespace(namespace)) {
return name;
}
}
if (namespace != null) {
try {
UUID playerID = UUID.fromString(namespace);
Profile profile = WorldGuard.getInstance().getProfileCache().getIfPresent(playerID);
if (profile != null) {
return "#" + profile.getName() + ":" + name;
}
} catch (IllegalArgumentException ignored) {
}
}
// Fall back to the fully qualified name.
return getQualifiedName();
}
public Optional<String> getNamespace() {
return Optional.ofNullable(namespace);
}
public String getName() {
return name;
}
public static boolean isValidNamespace(String namespace) {
if (namespace == null) {
return true;
}
return VALID_NAME_PATTERN.matcher(namespace).matches();
}
public static boolean isValidName(String name) {
checkNotNull(name);
return VALID_NAME_PATTERN.matcher(name).matches();
}
}
@@ -21,9 +21,9 @@ package com.sk89q.worldguard.protection.util;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.sk89q.squirrelid.Profile;
import com.sk89q.squirrelid.resolver.ProfileService;
import com.sk89q.squirrelid.util.UUIDs;
import com.sk89q.worldguard.util.profile.Profile;
import com.sk89q.worldguard.util.profile.resolver.ProfileService;
import com.sk89q.worldguard.util.profile.util.UUIDs;
import com.sk89q.worldguard.domains.DefaultDomain;
import javax.annotation.Nullable;
@@ -41,7 +41,6 @@ import com.sk89q.worldguard.session.handler.TimeLockFlag;
import com.sk89q.worldguard.session.handler.WaterBreathing;
import com.sk89q.worldguard.session.handler.WeatherLockFlag;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Arrays;
@@ -61,25 +60,19 @@ public abstract class AbstractSessionManager implements SessionManager {
private final LoadingCache<WorldPlayerTuple, Boolean> bypassCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterAccess(2, TimeUnit.SECONDS)
.build(new CacheLoader<WorldPlayerTuple, Boolean>() {
@Override
public Boolean load(@Nonnull WorldPlayerTuple tuple) throws Exception {
return tuple.getPlayer().hasPermission("worldguard.region.bypass." + tuple.getWorld().getName());
}
});
.build(CacheLoader.from(tuple ->
tuple.getPlayer().hasPermission("worldguard.region.bypass." + tuple.getWorld().getName())));
private final LoadingCache<CacheKey, Session> sessions = CacheBuilder.newBuilder()
.expireAfterAccess(SESSION_LIFETIME, TimeUnit.MINUTES)
.build(new CacheLoader<CacheKey, Session>() {
@Override
public Session load(@Nonnull CacheKey key) throws Exception {
return createSession(key.playerRef.get());
}
});
.build(CacheLoader.from(key ->
createSession(key.playerRef.get())));
private boolean hasCustom = false;
private List<Handler.Factory<? extends Handler>> handlers = new LinkedList<>();
private static final List<Handler.Factory<? extends Handler>> defaultHandlers = new LinkedList<>();
static {
Handler.Factory<?>[] factories = {
HealFlag.FACTORY,
@@ -104,12 +97,17 @@ public abstract class AbstractSessionManager implements SessionManager {
handlers.addAll(defaultHandlers);
}
@Override
public boolean customHandlersRegistered() {
return hasCustom;
}
@Override
public boolean registerHandler(Handler.Factory<? extends Handler> factory, @Nullable Handler.Factory<? extends Handler> after) {
if (factory == null) return false;
WorldGuard.logger.log(Level.INFO, "Registering session handler "
+ factory.getClass().getEnclosingClass().getName());
hasCustom = true;
if (after == null) {
handlers.add(factory);
} else {
@@ -135,7 +133,9 @@ public abstract class AbstractSessionManager implements SessionManager {
@Override
public boolean hasBypass(LocalPlayer player, World world) {
return bypassCache.getUnchecked(new WorldPlayerTuple(world, player));
Session sess = getIfPresent(player);
return sess != null && !sess.hasBypassDisabled()
&& bypassCache.getUnchecked(new WorldPlayerTuple(world, player));
}
@Override
@@ -44,6 +44,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class Session {
private final SessionManager manager;
private boolean disableBypass;
private final HashMap<Class<?>, Handler> handlers = Maps.newLinkedHashMap();
private Location lastValid;
private Set<ProtectedRegion> lastRegionSet;
@@ -217,4 +218,18 @@ public class Session {
return null;
}
/**
* @return true if the owner of this session should not bypass protection, even if they have bypass permissions
*/
public boolean hasBypassDisabled() {
return disableBypass;
}
/**
* Toggle bypass disabling for this session.
* @param disabled true to disable region bypass
*/
public void setBypassDisabled(boolean disabled) {
disableBypass = disabled;
}
}
@@ -54,6 +54,11 @@ public interface SessionManager {
*/
void resetState(LocalPlayer player);
/**
* @return true if custom handlers are or were at some point registered, false otherwise
*/
boolean customHandlersRegistered();
/**
* Register a handler with the BukkitSessionManager.
*
@@ -39,7 +39,7 @@ public class TimeLockFlag extends FlagValueChangeHandler<String> {
}
}
private Long initialTime;
private long initialTime;
private boolean initialRelative;
private static Pattern timePattern = Pattern.compile("([+\\-])?\\d+");
@@ -54,10 +54,7 @@ public class TimeLockFlag extends FlagValueChangeHandler<String> {
return;
}
boolean relative = value.startsWith("+") || value.startsWith("-");
Long time = Long.valueOf(value);
// if (!relative && (time < 0L || time > 24000L)) { // invalid time, reset to 0
// time = 0L;
// }
long time = Long.parseLong(value);
player.setPlayerTime(time, relative);
}
@@ -70,15 +67,20 @@ public class TimeLockFlag extends FlagValueChangeHandler<String> {
@Override
protected boolean onSetValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, String currentValue, String lastValue, MoveType moveType) {
if (lastValue == null) {
initialRelative = player.isPlayerTimeRelative();
initialTime = player.getPlayerTimeOffset();
}
updatePlayerTime(player, currentValue);
return true;
}
@Override
protected boolean onAbsentValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, String lastValue, MoveType moveType) {
// in the case that time = 0 and relative = true, this is the same as resetPlayerTime
player.setPlayerTime(initialTime, initialRelative);
initialRelative = true;
initialTime = 0L;
initialRelative = true;
return true;
}
@@ -45,16 +45,17 @@ public class WeatherLockFlag extends FlagValueChangeHandler<WeatherType> {
@Override
protected void onInitialValue(LocalPlayer player, ApplicableRegionSet set, WeatherType value) {
if (value == null) {
initialWeather = null;
return;
initialWeather = player.getPlayerWeather();
if (value != null) {
player.setPlayerWeather(value);
}
initialWeather = value;
player.setPlayerWeather(value);
}
@Override
protected boolean onSetValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, WeatherType currentValue, WeatherType lastValue, MoveType moveType) {
if (lastValue == null) {
initialWeather = player.getPlayerWeather();
}
player.setPlayerWeather(currentValue);
return true;
}
@@ -19,6 +19,8 @@
package com.sk89q.worldguard.util.concurrent;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
@@ -43,11 +45,28 @@ public final class EvenMoreExecutors {
* @return the newly created thread pool
*/
public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize) {
return newBoundedCachedThreadPool(minThreads, maxThreads, queueSize, null);}
/**
* Creates a thread pool that creates new threads as needed up to
* a maximum number of threads, but will reuse previously constructed
* threads when they are available.
*
* @param minThreads the minimum number of threads to have at a given time
* @param maxThreads the maximum number of threads to have at a given time
* @param queueSize the size of the queue before new submissions are rejected
* @param threadFormat thread name formatter
* @return the newly created thread pool
*/
public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize, String threadFormat) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
minThreads, maxThreads,
60L, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(queueSize));
threadPoolExecutor.allowCoreThreadTimeOut(true);
if (threadFormat != null) {
threadPoolExecutor.setThreadFactory(new ThreadFactoryBuilder().setNameFormat(threadFormat).build());
}
return threadPoolExecutor;
}
@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util.formatting.component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util.formatting.component;
import com.sk89q.worldedit.util.formatting.component.TextComponentProducer;
@@ -0,0 +1,54 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util.report;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.report.DataReport;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
public class ApplicableRegionsReport extends DataReport {
public ApplicableRegionsReport(LocalPlayer player) {
super("Applicable regions");
BlockVector3 position = player.getBlockIn().toVector().toBlockPoint();
append("Location", player.getWorld().getName() + " @ " + position);
RegionManager mgr = WorldGuard.getInstance().getPlatform().getRegionContainer().get(player.getWorld());
if (mgr == null) {
append("Regions", "Disabled for current world");
} else {
ApplicableRegionSet rgs = mgr.getApplicableRegions(position);
if (rgs.getRegions().isEmpty()) {
append("Regions", "None");
} else {
DataReport regions = new DataReport("Regions");
for (ProtectedRegion region : rgs.getRegions()) {
boolean inherited = !region.contains(position);
regions.append(region.getId() + (inherited ? "*" : ""), new RegionReport(region));
}
append(regions.getTitle(), regions);
}
}
}
}
@@ -32,9 +32,11 @@ public class RegionReport extends DataReport {
append("Type", region.getType());
append("Priority", region.getPriority());
append("Parent", region.getParent() == null ? "<none>" : region.getParent().getId());
append("Owners", region.getOwners());
append("Members", region.getMembers());
append("Flags", region.getFlags());
append("Bounds", region.getMinimumPoint() + " -> " + region.getMaximumPoint());
}
}
Loaded 100 of 106 files, more files were not shown because too many files have changed in this diff. Show more