Merge branch 'master' into fix/quoted

This commit is contained in:
Kenzie Togami 2019-07-27 17:41:44 -07:00
commit d134820bcb
No known key found for this signature in database
GPG Key ID: 5D200B325E157A81
92 changed files with 1767 additions and 1637 deletions

View File

@ -1,3 +1,27 @@
7.0.1 Release Candidate 1
- Improve //naturalize over large areas
- Fixed //restore with 1.14 worlds
- Added item brush support to WorldEdit for Bukkit (Formerly just Forge)
- Create an internal state ID mapping for performance
- Improve rotation for some blocks
- Added .self permission node to undo/redo to only allow undoing and redoing own history
- Improve sponge schematic implementation
- Re-add the delchunks command
- Added 1.14 blocks, items, tags, etc to the API (Remains compatible with 1.13)
- Made the navigation and selection wands normal tools that can be rebound per-user with //selwand and //navwand
- Added //wand -n to get the navigation wand
- Improved movement of paintings
- Allow command suggestions for selectors
- Allow block replacer to work with tile entities
- Fixed pasting leashed entities
- Fixed setting player heads with names
- Added a mask flag to //count
- Setup pagination for //distr
- Fixed an entity-related error being caused by plugins improperly using Spigot.
- Fixed gravity brush
- Modify chunk batching for performance
- Further legacy schematic loading improvements
7.0.0
See https://matthewmiller.dev/blog/introducing-worldedit-7/ for a friendlier explanation of some new features

View File

@ -1,159 +0,0 @@
buildscript {
repositories {
mavenCentral()
maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" }
jcenter()
}
configurations.all {
resolutionStrategy {
force 'commons-io:commons-io:2.4'
}
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.8.1'
}
}
plugins {
id 'net.minecrell.licenser' version '0.4.1' apply false
id "org.ajoberstar.grgit" version "2.3.0"
}
println """
*******************************************
You are building WorldEdit!
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 Discord! https://discord.gg/enginehub
Output files will be in [subproject]/build/libs
*******************************************
"""
allprojects {
group = 'com.sk89q.worldedit'
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") && !JavaVersion.current().isJava6()) {
try {
def repo = grgit.open()
ext.gitCommitHash = repo.head().abbreviatedId
} catch (Exception e) {
println "Error getting commit hash: " + e.getMessage()
}
}
if (!project.hasProperty("gitCommitHash")) {
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
ivy = false
}
}
}
artifactoryPublish.skip = true
subprojects {
repositories {
mavenCentral()
maven { url "http://maven.sk89q.com/repo/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
configurations.all {
resolutionStrategy {
cacheChangingModulesFor 5, 'minutes'
}
}
}
configure(['core', 'bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) {
apply plugin: 'java'
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 + ";" + 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'
if (JavaVersion.current().isJava8Compatible()) {
// Java 8 turns on doclint which we fail
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
}
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives jar
archives javadocJar
}
if (name == "worldedit-core" || name == "worldedit-bukkit") {
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
artifacts {
archives sourcesJar
}
build.dependsOn(sourcesJar)
}
build.dependsOn(checkstyleMain)
build.dependsOn(checkstyleTest)
build.dependsOn(javadocJar)
artifactoryPublish {
publishConfigs('archives')
}
license {
header = rootProject.file("HEADER.txt")
include '**/*.java'
}
}
configure(['bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) {
shadowJar {
classifier 'dist'
dependencies {
include(project(":worldedit-libs:core"))
include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}"))
include(project(":worldedit-core"))
}
exclude 'GradleStart**'
exclude '.cache'
exclude 'LICENSE*'
}
}

28
build.gradle.kts Normal file
View File

@ -0,0 +1,28 @@
import org.ajoberstar.grgit.Grgit
logger.lifecycle("""
*******************************************
You are building WorldEdit!
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 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"
}
}

36
buildSrc/build.gradle.kts Normal file
View File

@ -0,0 +1,36 @@
plugins {
`kotlin-dsl`
kotlin("jvm") version embeddedKotlinVersion
}
repositories {
jcenter()
gradlePluginPortal()
maven {
name = "Forge Maven"
url = uri("https://files.minecraftforge.net/maven")
}
}
configurations.all {
resolutionStrategy {
// Fabric needs this.
force(
"commons-io:commons-io:2.5",
"org.ow2.asm:asm:7.1",
"org.ow2.asm:asm-commons:7.1"
)
}
}
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")
implementation("gradle.plugin.org.spongepowered:spongegradle:0.9.0")
implementation("net.minecraftforge.gradle:ForgeGradle:3.0.130")
}

View File

@ -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() {
tasks.named<ArtifactoryTask>("artifactoryPublish") {
publishConfigs("archives")
}
}

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")
}
}
}

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

View File

@ -0,0 +1,98 @@
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}.worldedit-libs"
tasks.register<ShadowJar>("jar") {
configurations = listOf(project.configurations["shade"])
archiveClassifier.set("")
dependencies {
exclude(dependency("com.google.guava:guava"))
exclude(dependency("com.google.code.gson:gson"))
exclude(dependency("org.checkerframework:checker-qual"))
}
relocate("net.kyori.text", "com.sk89q.worldedit.util.formatting.text")
}
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("(.*)net/kyori/text((?:/|$).*)")
val textPattern = Regex("net\\.kyori\\.text")
eachFile {
filter {
it.replaceFirst(textPattern, "com.sk89q.worldedit.util.formatting.text")
}
path = path.replaceFirst(filePattern, "$1com/sk89q/worldedit/util/formatting/text$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()
}

View File

@ -0,0 +1,112 @@
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 {
useJUnitPlatform()
}
dependencies {
"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 == "worldedit-core" || name == "worldedit-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(":worldedit-libs:core"))
include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}"))
include(project(":worldedit-core"))
}
exclude("GradleStart**")
exclude(".cache")
exclude("LICENSE*")
minimize()
}
}

View File

@ -0,0 +1,7 @@
object Versions {
const val TEXT = "3.0.1"
const val TEXT_EXTRAS = "3.0.2"
const val PISTON = "0.4.3"
const val AUTO_VALUE = "1.6.5"
const val JUNIT = "5.5.0"
}

View File

@ -1,4 +1,4 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
#org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
group=com.sk89q.worldedit
version=7.0.1-SNAPSHOT
org.gradle.jvmargs=-Xmx1G

Binary file not shown.

View File

@ -1,6 +1,5 @@
#Thu Mar 14 00:19:48 PDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip

18
gradlew vendored
View File

@ -1,5 +1,21 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

18
gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

View File

@ -1,11 +0,0 @@
rootProject.name = 'worldedit'
include 'worldedit-libs'
['bukkit', 'core', 'forge', 'sponge', 'fabric'].forEach {
include "worldedit-libs:$it"
include "worldedit-$it"
}
include "worldedit-libs:core:ap"
include "worldedit-core:doctools"

11
settings.gradle.kts Normal file
View File

@ -0,0 +1,11 @@
rootProject.name = "worldedit"
include("worldedit-libs")
listOf("bukkit", "core", "forge", "sponge", "fabric").forEach {
include("worldedit-libs:$it")
include("worldedit-$it")
}
include("worldedit-libs:core:ap")
include("worldedit-core:doctools")

View File

@ -1,63 +0,0 @@
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'maven'
apply plugin: 'java-library'
repositories {
maven { url "https://hub.spigotmc.org/nexus/content/groups/public" }
maven { url "https://repo.codemc.org/repository/maven-public" }
maven { url "https://papermc.io/repo/repository/maven-public/" }
}
configurations.all { Configuration it ->
it.resolutionStrategy { ResolutionStrategy rs ->
rs.force("com.google.guava:guava:21.0")
}
}
dependencies {
api project(':worldedit-core')
api project(':worldedit-libs:bukkit')
api 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz
compileOnly 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT'
implementation 'io.papermc:paperlib:1.0.2'
compileOnly 'com.sk89q:dummypermscompat:1.10'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'
implementation 'org.bstats:bstats-bukkit:1.5'
testCompile 'org.mockito:mockito-core:1.9.0-rc1'
}
processResources {
filesMatching('plugin.yml') {
expand 'internalVersion': project.internalVersion
}
from (zipTree('src/main/resources/worldedit-adapters.jar').matching {
exclude 'META-INF/'
})
exclude '**/worldedit-adapters.jar'
}
jar {
manifest {
attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version": version)
}
}
shadowJar {
dependencies {
relocate "org.slf4j", "com.sk89q.worldedit.slf4j"
relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge"
include(dependency(':worldedit-core'))
include(dependency('org.slf4j:slf4j-api'))
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
relocate ("org.bstats", "com.sk89q.worldedit.bukkit.bstats") {
include(dependency("org.bstats:bstats-bukkit:1.5"))
}
relocate ("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") {
include(dependency("io.papermc:paperlib:1.0.2"))
}
}
}
build.dependsOn(shadowJar)

View File

@ -0,0 +1,71 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
`java-library`
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
repositories {
maven { url = uri("https://hub.spigotmc.org/nexus/content/groups/public") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
}
configurations.all {
resolutionStrategy {
force("com.google.guava:guava:21.0")
}
}
dependencies {
"api"(project(":worldedit-core"))
"api"(project(":worldedit-libs:bukkit"))
"api"("org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT") {
exclude("junit", "junit")
}
"compileOnly"("com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT")
"implementation"("io.papermc:paperlib:1.0.2")
"compileOnly"("com.sk89q:dummypermscompat:1.10")
"implementation"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1")
"implementation"("org.bstats:bstats-bukkit:1.5")
"testCompile"("org.mockito:mockito-core:1.9.0-rc1")
}
tasks.named<Copy>("processResources") {
filesMatching("plugin.yml") {
expand("internalVersion" to project.ext["internalVersion"])
}
from(zipTree("src/main/resources/worldedit-adapters.jar").matching {
exclude("META-INF/")
})
exclude("**/worldedit-adapters.jar")
}
tasks.named<Jar>("jar") {
manifest {
attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("shadowJar") {
dependencies {
relocate("org.slf4j", "com.sk89q.worldedit.slf4j")
relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge")
include(dependency(":worldedit-core"))
include(dependency("org.slf4j:slf4j-api"))
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
relocate("org.bstats", "com.sk89q.worldedit.bukkit.bstats") {
include(dependency("org.bstats:bstats-bukkit:1.5"))
}
relocate("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") {
include(dependency("io.papermc:paperlib:1.0.2"))
}
}
}
tasks.named("assemble").configure {
dependsOn("shadowJar")
}

View File

@ -335,7 +335,11 @@ public class BukkitAdapter {
* @return WorldEdit EntityType
*/
public static EntityType adapt(org.bukkit.entity.EntityType entityType) {
return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT));
final String name = entityType.getName();
if (name == null) {
return null;
}
return EntityTypes.get(name.toLowerCase(Locale.ROOT));
}
public static org.bukkit.entity.EntityType adapt(EntityType entityType) {

View File

@ -185,14 +185,13 @@ public class BukkitPlayer extends AbstractPlayerActor {
}
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
if (alwaysGlass || !player.getAllowFlight()) {
super.floatAt(x, y, z, alwaysGlass);
return;
public boolean isAllowedToFly() {
return player.getAllowFlight();
}
setPosition(Vector3.at(x + 0.5, y, z + 0.5));
player.setFlying(true);
@Override
public void setFlying(boolean flying) {
player.setFlying(flying);
}
@Override

View File

@ -316,15 +316,16 @@ public class BukkitWorld extends AbstractWorld {
@Override
public boolean equals(Object other) {
if (worldRef.get() == null) {
final World ref = worldRef.get();
if (ref == null) {
return false;
} else if (other == null) {
return false;
} else if ((other instanceof BukkitWorld)) {
World otherWorld = ((BukkitWorld) other).worldRef.get();
return otherWorld != null && otherWorld.equals(getWorld());
return ref.equals(otherWorld);
} else if (other instanceof com.sk89q.worldedit.world.World) {
return ((com.sk89q.worldedit.world.World) other).getName().equals(getName());
return ((com.sk89q.worldedit.world.World) other).getName().equals(ref.getName());
} else {
return false;
}

View File

@ -96,7 +96,6 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class);
public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui";
private static WorldEditPlugin INSTANCE;
private static WorldInitListener worldInitListener = null;
private BukkitImplAdapter bukkitAdapter;
private BukkitServerInterface server;
@ -139,22 +138,19 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
getServer().getPluginManager().registerEvents(new AsyncTabCompleteListener(), this);
}
initializeRegistries(); // this creates the objects matching Bukkit's enums - but doesn't fill them with data yet
if (Bukkit.getWorlds().isEmpty()) {
setupPreWorldData();
// register this so we can load world-dependent data right as the first world is loading
if (worldInitListener != null) {
getServer().getPluginManager().registerEvents(new WorldInitListener(), this);
} else {
getLogger().warning("Server reload detected. This may cause various issues with WorldEdit and dependent plugins.");
try {
// these don't stick around between reload
loadAdapter();
loadConfig();
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
setupPreWorldData();
// since worlds are loaded already, we can do this now
setupWorldData();
} catch (Throwable ignored) {
}
} else {
getServer().getPluginManager().registerEvents((worldInitListener = new WorldInitListener()), this);
loadAdapter(); // Need an adapter to work with special blocks with NBT data
setupRegistries();
WorldEdit.getInstance().loadMappings();
loadConfig(); // Load configuration
}
// Enable metrics
@ -162,12 +158,19 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
PaperLib.suggestPaper(this);
}
private void setupPreWorldData() {
loadAdapter();
loadConfig();
WorldEdit.getInstance().loadMappings();
}
private void setupWorldData() {
setupTags();
setupTags(); // datapacks aren't loaded until just before the world is, and bukkit has no event for this
// so the earliest we can do this is in WorldInit
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
}
private void setupRegistries() {
private void initializeRegistries() {
// Biome
for (Biome biome : Biome.values()) {
String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT);
@ -487,9 +490,9 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
if (!event.isCommand()) return;
String buffer = event.getBuffer();
final String[] parts = buffer.split(" ");
if (parts.length < 1) return;
final String label = parts[0];
int firstSpace = buffer.indexOf(' ');
if (firstSpace < 0) return;
final String label = buffer.substring(0, firstSpace);
final Optional<org.enginehub.piston.Command> command
= WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(label);
if (!command.isPresent()) return;

View File

@ -19,20 +19,20 @@
package com.sk89q.wepif;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.bukkit.Server;
import org.bukkit.plugin.PluginManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class DinnerPermsResolverTest {
private DinnerPermsResolver resolver;
@Before
@BeforeEach
public void setUp() {
Server server = mock(Server.class);
when(server.getPluginManager()).thenReturn(mock(PluginManager.class));

View File

@ -20,15 +20,16 @@
package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.util.TreeGenerator;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class BukkitWorldTest {
@Test
public void testTreeTypeMapping() {
for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) {
Assert.assertNotNull("No mapping for: " + type, BukkitWorld.toBukkitTreeType(type));
assertNotNull(BukkitWorld.toBukkitTreeType(type), "No mapping for: " + type);
}
}

View File

@ -1,52 +0,0 @@
plugins {
id("net.ltgt.apt") version "0.21"
}
apply plugin: 'java-library'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'net.ltgt.apt-eclipse'
apply plugin: 'net.ltgt.apt-idea'
configurations.all { Configuration it ->
it.resolutionStrategy { ResolutionStrategy rs ->
rs.force("com.google.guava:guava:21.0")
}
}
dependencies {
compile project(':worldedit-libs:core')
compile 'de.schlichtherle:truezip:6.8.3'
compile 'rhino:js:1.7R2'
compile 'org.yaml:snakeyaml:1.9'
compile 'com.google.guava:guava:21.0'
compile 'com.google.code.findbugs:jsr305:1.3.9'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.googlecode.json-simple:json-simple:1.1.1'
compile 'org.slf4j:slf4j-api:1.7.26'
compileOnly project(':worldedit-libs:core:ap')
annotationProcessor project(':worldedit-libs:core:ap')
annotationProcessor "com.google.guava:guava:21.0"
def avVersion = "1.6.5"
compileOnly "com.google.auto.value:auto-value-annotations:$avVersion"
annotationProcessor "com.google.auto.value:auto-value:$avVersion"
//compile 'net.sf.trove4j:trove4j:3.0.3'
testCompile 'org.mockito:mockito-core:1.9.0-rc1'
}
tasks.withType(JavaCompile).configureEach {
it.options.compilerArgs.add("-Aarg.name.key.prefix=")
}
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir 'src/legacy/java'
}
resources {
srcDir 'src/main/resources'
}
}
}

View File

@ -0,0 +1,49 @@
plugins {
id("java-library")
id("net.ltgt.apt-eclipse")
id("net.ltgt.apt-idea")
}
applyPlatformAndCoreConfiguration()
configurations.all {
resolutionStrategy {
force("com.google.guava:guava:21.0")
}
}
dependencies {
"compile"(project(":worldedit-libs:core"))
"compile"("de.schlichtherle:truezip:6.8.3")
"compile"("org.mozilla:rhino:1.7.11")
"compile"("org.yaml:snakeyaml:1.9")
"compile"("com.google.guava:guava:21.0")
"compile"("com.google.code.findbugs:jsr305:1.3.9")
"compile"("com.google.code.gson:gson:2.8.0")
"compile"("org.slf4j:slf4j-api:1.7.26")
"compileOnly"(project(":worldedit-libs:core:ap"))
"annotationProcessor"(project(":worldedit-libs:core:ap"))
// ensure this is on the classpath for the AP
"annotationProcessor"("com.google.guava:guava:21.0")
"compileOnly"("com.google.auto.value:auto-value-annotations:${Versions.AUTO_VALUE}")
"annotationProcessor"("com.google.auto.value:auto-value:${Versions.AUTO_VALUE}")
"testCompile"("org.mockito:mockito-core:1.9.0-rc1")
}
tasks.withType<JavaCompile>().configureEach {
dependsOn(":worldedit-libs:build")
options.compilerArgs.add("-Aarg.name.key.prefix=")
}
sourceSets {
main {
java {
srcDir("src/main/java")
srcDir("src/legacy/java")
}
resources {
srcDir("src/main/resources")
}
}
}

View File

@ -1,17 +1,15 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.3.31"
kotlin("jvm") version "1.3.41"
}
applyCommonConfiguration()
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
repositories {
jcenter()
}
dependencies {
"implementation"(project(":worldedit-libs:core:ap"))
"implementation"(project(":worldedit-core"))

View File

@ -180,7 +180,8 @@ public class BiomeCommands {
Mask2D mask2d = mask != null ? mask.toMask2D() : null;
if (atPosition) {
region = new CuboidRegion(player.getLocation().toVector().toBlockPoint(), player.getLocation().toVector().toBlockPoint());
final BlockVector3 pos = player.getLocation().toVector().toBlockPoint();
region = new CuboidRegion(pos, pos);
} else {
region = session.getSelection(world);
}

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo;
@ -34,6 +35,7 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
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;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
@ -50,8 +52,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
@ -93,11 +95,11 @@ public class ChunkCommands {
@CommandPermissions("worldedit.listchunks")
public void listChunks(Player player, LocalSession session,
@ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException {
Set<BlockVector2> chunks = session.getSelection(player.getWorld()).getChunks();
final Region region = session.getSelection(player.getWorld());
PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%",
chunks.stream().map(BlockVector2::toString).collect(Collectors.toList()));
player.print(paginationBox.create(page));
WorldEditAsyncCommandBuilder.createAndSendMessage(player,
() -> new ChunkListPaginationBox(region).create(page),
"Listing chunks for " + player.getName());
}
@Command(
@ -134,8 +136,8 @@ public class ChunkCommands {
newBatch.backup = true;
final Region selection = session.getSelection(player.getWorld());
if (selection instanceof CuboidRegion) {
newBatch.minChunk = BlockVector2.at(selection.getMinimumPoint().getBlockX() >> 4, selection.getMinimumPoint().getBlockZ() >> 4);
newBatch.maxChunk = BlockVector2.at(selection.getMaximumPoint().getBlockX() >> 4, selection.getMaximumPoint().getBlockZ() >> 4);
newBatch.minChunk = selection.getMinimumPoint().shr(4).toBlockVector2();
newBatch.maxChunk = selection.getMaximumPoint().shr(4).toBlockVector2();
} else {
// this has a possibility to OOM for very large selections still
Set<BlockVector2> chunks = selection.getChunks();
@ -168,4 +170,27 @@ public class ChunkCommands {
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop"))));
}
private static class ChunkListPaginationBox extends PaginationBox {
//private final Region region;
private final List<BlockVector2> chunks;
ChunkListPaginationBox(Region region) {
super("Selected Chunks", "/listchunks -p %page%");
// TODO make efficient/streamable/calculable implementations of this
// for most region types, so we can just store the region and random-access get one page of chunks
// (this is non-trivial for some types of selections...)
//this.region = region.clone();
this.chunks = new ArrayList<>(region.getChunks());
}
@Override
public Component getComponent(int number) {
return TextComponent.of(chunks.get(number).toString());
}
@Override
public int getComponentsSize() {
return chunks.size();
}
}
}

View File

@ -162,13 +162,13 @@ public class GenerationCommands {
final double radiusX, radiusY, radiusZ;
switch (radii.size()) {
case 1:
radiusX = radiusY = radiusZ = Math.max(1, radii.get(0));
radiusX = radiusY = radiusZ = Math.max(0, radii.get(0));
break;
case 3:
radiusX = Math.max(1, radii.get(0));
radiusY = Math.max(1, radii.get(1));
radiusZ = Math.max(1, radii.get(2));
radiusX = Math.max(0, radii.get(0));
radiusY = Math.max(0, radii.get(1));
radiusZ = Math.max(0, radii.get(2));
break;
default:
@ -205,7 +205,7 @@ public class GenerationCommands {
@Arg(desc = "The density of the forest, between 0 and 100", def = "5")
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
density = density / 100;
density /= 100;
int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
player.print(affected + " trees created.");
return affected;

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.command;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@ -42,10 +44,10 @@ import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.formatting.component.CodeFormat;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox;
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;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.io.Closer;
import com.sk89q.worldedit.util.io.file.FilenameException;
@ -68,7 +70,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
@ -404,4 +408,44 @@ public class SchematicCommands {
}
return fileList;
}
private static class SchematicPaginationBox extends PaginationBox {
private final String prefix;
private final File[] files;
SchematicPaginationBox(String rootDir, File[] files, String pageCommand) {
super("Available schematics", pageCommand);
this.prefix = rootDir == null ? "" : rootDir;
this.files = files;
}
@Override
public Component getComponent(int number) {
checkArgument(number < files.length && number >= 0);
File file = files[number];
Multimap<String, ClipboardFormat> exts = ClipboardFormats.getFileExtensionMap();
String format = exts.get(Files.getFileExtension(file.getName()))
.stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown");
boolean inRoot = file.getParentFile().getName().equals(prefix);
String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1];
return TextComponent.builder()
.content("")
.append(TextComponent.of("[L]")
.color(TextColor.GOLD)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load"))))
.append(TextComponent.space())
.append(TextComponent.of(path)
.color(TextColor.DARK_GREEN)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format))))
.build();
}
@Override
public int getComponentsSize() {
return files.length;
}
}
}

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.command;
import com.google.common.base.Strings;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@ -56,16 +57,19 @@ import com.sk89q.worldedit.regions.selector.SphereRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.BlockDistributionResult;
import com.sk89q.worldedit.util.formatting.component.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.component.TextComponentProducer;
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;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.storage.ChunkStore;
@ -570,7 +574,7 @@ public class SelectionCommands {
}
case LIST:
default:
CommandListBox box = new CommandListBox("Selection modes", null);
CommandListBox box = new CommandListBox("Selection modes", null, null);
box.setHidingHelp(true);
TextComponentProducer contents = box.getContents();
contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline();
@ -608,4 +612,62 @@ public class SelectionCommands {
session.dispatchCUISelection(player);
}
private static class BlockDistributionResult extends PaginationBox {
private final List<Countable<BlockState>> distribution;
private final int totalBlocks;
private final boolean separateStates;
BlockDistributionResult(List<Countable<BlockState>> distribution, boolean separateStates) {
super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : ""));
this.distribution = distribution;
// note: doing things like region.getArea is inaccurate for non-cuboids.
this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum();
this.separateStates = separateStates;
setComponentsPerPage(7);
}
@Override
public Component getComponent(int number) {
Countable<BlockState> c = distribution.get(number);
TextComponent.Builder line = TextComponent.builder();
final int count = c.getAmount();
final double perc = count / (double) totalBlocks * 100;
final int maxDigits = (int) (Math.log10(totalBlocks) + 1);
final int curDigits = (int) (Math.log10(count) + 1);
line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD);
final int space = maxDigits - curDigits;
String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1);
line.append(String.format("%s%s", count, pad), TextColor.YELLOW);
final BlockState state = c.getID();
final BlockType blockType = state.getBlockType();
TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE);
TextComponent toolTip;
if (separateStates && state != blockType.getDefaultState()) {
toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY);
blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE));
} else {
toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY);
}
blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip));
line.append(blockName);
return line.build();
}
@Override
public int getComponentsSize() {
return distribution.size();
}
@Override
public Component create(int page) throws InvalidComponentException {
super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY))
.append(TextComponent.newline());
return super.create(page);
}
}
}

View File

@ -523,7 +523,8 @@ public class UtilityCommands {
int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, listSubCommands, we, actor);
PrintCommandHelp.help(command, page, listSubCommands,
we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help");
}
}

View File

@ -164,6 +164,7 @@ public class WorldEditCommands {
int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, listSubCommands, we, actor);
PrintCommandHelp.help(command, page, listSubCommands,
we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help");
}
}

View File

@ -92,7 +92,7 @@ public class BrushTool implements TraceTool {
* @return the mask used to stop block traces
*/
public @Nullable Mask getTraceMask() {
return mask;
return this.traceMask;
}
/**

View File

@ -23,12 +23,13 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.util.LocatedBlock;
import com.sk89q.worldedit.util.collection.LocatedBlockList;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.LinkedHashSet;
import java.util.Set;
public class GravityBrush implements Brush {
@ -40,27 +41,60 @@ public class GravityBrush implements Brush {
@Override
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException {
final double startY = fullHeight ? editSession.getWorld().getMaxY() : position.getBlockY() + size;
for (double x = position.getBlockX() + size; x > position.getBlockX() - size; --x) {
for (double z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) {
double y = startY;
final List<BlockState> blockTypes = new ArrayList<>();
for (; y > position.getBlockY() - size; --y) {
final BlockVector3 pt = BlockVector3.at(x, y, z);
final BlockState block = editSession.getBlock(pt);
if (!block.getBlockType().getMaterial().isAir()) {
blockTypes.add(block);
editSession.setBlock(pt, BlockTypes.AIR.getDefaultState());
}
}
double yMax = fullHeight ? editSession.getWorld().getMaxY() : position.getY() + size;
double yMin = Math.max(position.getY() - size, 0);
LocatedBlockList column = new LocatedBlockList();
Set<BlockVector3> removedBlocks = new LinkedHashSet<>();
for (double x = position.getX() - size; x <= position.getX() + size; x++) {
for (double z = position.getZ() - size; z <= position.getZ() + size; z++) {
/*
* Algorithm:
* 1. Find lowest air block in the selection -> $lowestAir = position
* 2. Move the first non-air block above it down to $lowestAir
* 3. Add 1 to $lowestAir's y-coord.
* 4. If more blocks above current position, repeat from 2
*/
BlockVector3 lowestAir = null;
for (double y = yMin; y <= yMax; y++) {
BlockVector3 pt = BlockVector3.at(x, y, z);
Collections.reverse(blockTypes);
for (int i = 0; i < blockTypes.size();) {
if (editSession.getBlock(pt).getBlockType().getMaterial().isAir()) {
editSession.setBlock(pt, blockTypes.get(i++));
BaseBlock block = editSession.getFullBlock(pt);
if (block.getBlockType().getMaterial().isAir()) {
if (lowestAir == null) {
// we found the lowest air block
lowestAir = pt;
}
pt = pt.add(0, 1, 0);
continue;
}
if (lowestAir == null) {
// no place to move the block to
continue;
}
BlockVector3 newPos = lowestAir;
// we know the block above must be air,
// since either this block is being moved into it,
// or there has been more air before this block
lowestAir = lowestAir.add(0, 1, 0);
removedBlocks.remove(newPos);
column.add(newPos, block);
removedBlocks.add(pt);
}
for (LocatedBlock block : column) {
editSession.setBlock(block.getLocation(), block.getBlock());
}
for (BlockVector3 removedBlock : removedBlocks) {
editSession.setBlock(removedBlock, BlockTypes.AIR.getDefaultState());
}
column.clear();
removedBlocks.clear();
}
}
}

View File

@ -67,11 +67,11 @@ public class PrintCommandHelp {
return mapping.orElse(null);
}
public static void help(List<String> commandPath, int page, boolean listSubCommands, WorldEdit we, Actor actor) throws InvalidComponentException {
CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager();
public static void help(List<String> commandPath, int page, boolean listSubCommands,
CommandManager manager, Actor actor, String helpRootCommand) throws InvalidComponentException {
if (commandPath.isEmpty()) {
printCommands(page, manager.getAllCommands(), actor, ImmutableList.of());
printCommands(page, manager.getAllCommands(), actor, ImmutableList.of(), helpRootCommand);
return;
}
@ -93,7 +93,7 @@ public class PrintCommandHelp {
toCommandString(visited), subCommand));
// full help for single command
CommandUsageBox box = new CommandUsageBox(visited, visited.stream()
.map(Command::getName).collect(Collectors.joining(" ")));
.map(Command::getName).collect(Collectors.joining(" ")), helpRootCommand);
actor.print(box.create());
return;
}
@ -105,7 +105,7 @@ public class PrintCommandHelp {
actor.printError(String.format("The sub-command '%s' under '%s' could not be found.",
subCommand, toCommandString(visited)));
// list subcommands for currentCommand
printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited);
printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited, helpRootCommand);
return;
}
}
@ -114,10 +114,10 @@ public class PrintCommandHelp {
if (subCommands.isEmpty() || !listSubCommands) {
// Create the message
CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited));
CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited), helpRootCommand);
actor.print(box.create());
} else {
printCommands(page, subCommands.values().stream(), actor, visited);
printCommands(page, subCommands.values().stream(), actor, visited, helpRootCommand);
}
}
@ -126,7 +126,7 @@ public class PrintCommandHelp {
}
private static void printCommands(int page, Stream<Command> commandStream, Actor actor,
List<Command> commandList) throws InvalidComponentException {
List<Command> commandList, String helpRootCommand) throws InvalidComponentException {
// Get a list of aliases
List<Command> commands = commandStream
.sorted(byCleanName())
@ -135,7 +135,8 @@ public class PrintCommandHelp {
String used = commandList.isEmpty() ? null : toCommandString(commandList);
CommandListBox box = new CommandListBox(
(used == null ? "Help" : "Subcommands: " + used),
"//help -s -p %page%" + (used == null ? "" : " " + used));
helpRootCommand + " -s -p %page%" + (used == null ? "" : " " + used),
helpRootCommand);
if (!actor.isPlayer()) {
box.formatForConsole();
}

View File

@ -19,7 +19,10 @@
package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.NotABlockException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
@ -32,6 +35,7 @@ import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TargetBlock;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -173,7 +177,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
if (spots == 2) {
final BlockVector3 platform = BlockVector3.at(x, y - 2, z);
final BlockState block = world.getBlock(platform);
final com.sk89q.worldedit.world.block.BlockType type = block.getBlockType();
final BlockType type = block.getBlockType();
// Don't get put in lava!
if (type == BlockTypes.LAVA) {
@ -259,6 +263,13 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
// Found a ceiling!
if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) {
int platformY = Math.max(initialY, y - 3 - clearance);
if (platformY < initialY) { // if ==, they already have the given clearance, if <, clearance is too large
printError("Not enough space above you!");
return false;
} else if (platformY == initialY) {
printError("You're already at the ceiling.");
return false;
}
floatAt(x, platformY + 1, z, alwaysGlass);
return true;
}
@ -302,25 +313,49 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
try {
if (alwaysGlass || !isAllowedToFly()) {
BlockVector3 spot = BlockVector3.at(x, y - 1, z);
if (!getLocation().getExtent().getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) {
getLocation().getExtent().setBlock(spot, BlockTypes.GLASS.getDefaultState());
final World world = getWorld();
if (!world.getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) {
try (EditSession session = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 1, this)) {
session.setBlock(spot, BlockTypes.GLASS.getDefaultState());
} catch (MaxChangedBlocksException ignored) {
}
} catch (WorldEditException e) {
e.printStackTrace();
}
} else {
setFlying(true);
}
setPosition(Vector3.at(x + 0.5, y, z + 0.5));
}
/**
* Check whether the player is allowed to fly.
*
* @return true if allowed flight
*/
protected boolean isAllowedToFly() {
return false;
}
/**
* Set whether the player is currently flying.
*
* @param flying true to fly
*/
protected void setFlying(boolean flying) {
}
@Override
public Location getBlockIn() {
return getLocation().setPosition(getLocation().toVector().floor());
final Location location = getLocation();
return location.setPosition(location.toVector().floor());
}
@Override
public Location getBlockOn() {
return getLocation().setPosition(getLocation().setY(getLocation().getY() - 1).toVector().floor());
final Location location = getLocation();
return location.setPosition(location.setY(location.getY() - 1).toVector().floor());
}
@Override
@ -369,15 +404,16 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public Direction getCardinalDirection(int yawOffset) {
if (getLocation().getPitch() > 67.5) {
final Location location = getLocation();
if (location.getPitch() > 67.5) {
return Direction.DOWN;
}
if (getLocation().getPitch() < -67.5) {
if (location.getPitch() < -67.5) {
return Direction.UP;
}
// From hey0's code
double rot = (getLocation().getYaw() + yawOffset) % 360; //let's use real yaw now
double rot = (location.getYaw() + yawOffset) % 360; //let's use real yaw now
if (rot < 0) {
rot += 360.0;
}
@ -394,51 +430,62 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
}
}
private boolean canPassThroughBlock(Location curBlock) {
BlockVector3 blockPos = curBlock.toVector().toBlockPoint();
BlockState block = curBlock.getExtent().getBlock(blockPos);
return !block.getBlockType().getMaterial().isMovementBlocker();
}
/**
* Get the player's view yaw.
*
* @return yaw
* Advances the block target block until the current block is a wall
* @return true if a wall is found
*/
@Override
public boolean passThroughForwardWall(int range) {
int searchDist = 0;
TargetBlock hitBlox = new TargetBlock(this, range, 0.2);
Extent world = getLocation().getExtent();
Location block;
boolean firstBlock = true;
int freeToFind = 2;
boolean inFree = false;
while ((block = hitBlox.getNextBlock()) != null) {
boolean free = !world.getBlock(block.toVector().toBlockPoint()).getBlockType().getMaterial().isMovementBlocker();
if (firstBlock) {
firstBlock = false;
if (!free) {
--freeToFind;
continue;
}
}
++searchDist;
if (searchDist > 20) {
return false;
}
if (inFree != free) {
if (free) {
--freeToFind;
}
}
if (freeToFind == 0) {
setOnGround(block);
private boolean advanceToWall(TargetBlock hitBlox) {
Location curBlock;
while ((curBlock = hitBlox.getCurrentBlock()) != null) {
if (!canPassThroughBlock(curBlock)) {
return true;
}
inFree = free;
hitBlox.getNextBlock();
}
return false;
}
/**
* Advances the block target block until the current block is a free
* @return true if a free spot is found
*/
private boolean advanceToFree(TargetBlock hitBlox) {
Location curBlock;
while ((curBlock = hitBlox.getCurrentBlock()) != null) {
if (canPassThroughBlock(curBlock)) {
return true;
}
hitBlox.getNextBlock();
}
return false;
}
@Override
public boolean passThroughForwardWall(int range) {
TargetBlock hitBlox = new TargetBlock(this, range, 0.2);
if (!advanceToWall(hitBlox)) {
return false;
}
if (!advanceToFree(hitBlox)) {
return false;
}
Location foundBlock = hitBlox.getCurrentBlock();
if (foundBlock != null) {
setOnGround(foundBlock);
return true;
}
return false;
@ -446,7 +493,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public void setPosition(Vector3 pos) {
setPosition(pos, getLocation().getPitch(), getLocation().getYaw());
final Location location = getLocation();
setPosition(pos, location.getPitch(), location.getYaw());
}
@Override

View File

@ -178,4 +178,9 @@ class PlayerProxy extends AbstractPlayerActor {
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
basePlayer.sendFakeBlock(pos, block);
}
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
basePlayer.floatAt(x, y, z, alwaysGlass);
}
}

View File

@ -0,0 +1,67 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit 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.worldedit.extent;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Optional;
/**
* Base extent class for buffering changes between {@link #setBlock(BlockVector3, BlockStateHolder)}
* and the delegate extent. This class ensures that {@link #getBlock(BlockVector3)} is properly
* handled, by returning buffered blocks.
*/
public abstract class AbstractBufferingExtent extends AbstractDelegateExtent {
/**
* Create a new instance.
*
* @param extent the extent
*/
protected AbstractBufferingExtent(Extent extent) {
super(extent);
}
@Override
public abstract <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException;
protected final <T extends BlockStateHolder<T>> boolean setDelegateBlock(BlockVector3 location, T block) throws WorldEditException {
return super.setBlock(location, block);
}
@Override
public BlockState getBlock(BlockVector3 position) {
return getBufferedBlock(position)
.map(BaseBlock::toImmutableState)
.orElseGet(() -> super.getBlock(position));
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
return getBufferedBlock(position)
.orElseGet(() -> super.getFullBlock(position));
}
protected abstract Optional<BaseBlock> getBufferedBlock(BlockVector3 position);
}

View File

@ -21,16 +21,16 @@ package com.sk89q.worldedit.extent.buffer;
import com.google.common.collect.Maps;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Map;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
@ -38,7 +38,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
* Buffers changes to an {@link Extent} and allows retrieval of the changed blocks,
* without modifying the underlying extent.
*/
public class ExtentBuffer extends AbstractDelegateExtent {
public class ExtentBuffer extends AbstractBufferingExtent {
private final Map<BlockVector3, BaseBlock> buffer = Maps.newHashMap();
private final Mask mask;
@ -67,23 +67,11 @@ public class ExtentBuffer extends AbstractDelegateExtent {
}
@Override
public BlockState getBlock(BlockVector3 position) {
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (mask.test(position)) {
return getOrDefault(position).toImmutableState();
return Optional.of(buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos))));
}
return super.getBlock(position);
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
if (mask.test(position)) {
return getOrDefault(position);
}
return super.getFullBlock(position);
}
private BaseBlock getOrDefault(BlockVector3 position) {
return buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos)));
return Optional.empty();
}
@Override

View File

@ -206,6 +206,8 @@ public class MCEditSchematicReader extends NBTSchematicReader {
}
if (values.isEmpty()) {
t = null;
} else {
t = new CompoundTag(values);
}
if (fixer != null && t != null) {
@ -378,6 +380,24 @@ public class MCEditSchematicReader extends NBTSchematicReader {
return "note_block";
case "Structure":
return "structure_block";
case "Chest":
return "chest";
case "Sign":
return "sign";
case "Banner":
return "banner";
case "Beacon":
return "beacon";
case "Comparator":
return "comparator";
case "Dropper":
return "dropper";
case "Furnace":
return "furnace";
case "Hopper":
return "hopper";
case "Skull":
return "skull";
default:
return id;
}

View File

@ -111,7 +111,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
} else if (dataVersion < liveDataVersion) {
fixer = platform.getDataFixer();
if (fixer != null) {
log.info("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.",
log.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.",
dataVersion, liveDataVersion);
} else {
log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.",

View File

@ -260,8 +260,9 @@ public class SpongeSchematicWriter implements ClipboardWriter {
}
values.remove("id");
values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(e.getLocation().toVector()));
values.put("Rotation", writeRotation(e.getLocation()));
final Location location = e.getLocation();
values.put("Pos", writeVector(location.toVector()));
values.put("Rotation", writeRotation(location));
return new CompoundTag(values);
}).filter(Objects::nonNull).collect(Collectors.toList());

View File

@ -19,22 +19,25 @@
package com.sk89q.worldedit.extent.reorder;
import com.google.common.collect.Table;
import com.google.common.collect.TreeBasedTable;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.RunContext;
import com.sk89q.worldedit.function.operation.SetLocatedBlocks;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.collection.LocatedBlockList;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
* A special extent that batches changes into Minecraft chunks. This helps
@ -42,17 +45,19 @@ import java.util.TreeMap;
* loaded repeatedly, however it does take more memory due to caching the
* blocks.
*/
public class ChunkBatchingExtent extends AbstractDelegateExtent {
public class ChunkBatchingExtent extends AbstractBufferingExtent {
/**
* Comparator optimized for sorting chunks by the region file they reside
* in. This allows for file caches to be used while loading the chunk.
*/
private static final Comparator<BlockVector2> REGION_OPTIMIZED_SORT =
Comparator.comparing((BlockVector2 vec) -> vec.divide(32), BlockVector2.COMPARING_GRID_ARRANGEMENT)
Comparator.comparing((BlockVector2 vec) -> vec.shr(5), BlockVector2.COMPARING_GRID_ARRANGEMENT)
.thenComparing(BlockVector2.COMPARING_GRID_ARRANGEMENT);
private final SortedMap<BlockVector2, LocatedBlockList> batches = new TreeMap<>(REGION_OPTIMIZED_SORT);
private final Table<BlockVector2, BlockVector3, BaseBlock> batches =
TreeBasedTable.create(REGION_OPTIMIZED_SORT, BlockVector3.sortByCoordsYzx());
private final Set<BlockVector3> containedBlocks = new HashSet<>();
private boolean enabled;
public ChunkBatchingExtent(Extent extent) {
@ -76,16 +81,34 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
return enabled;
}
private BlockVector2 getChunkPos(BlockVector3 location) {
return location.shr(4).toBlockVector2();
}
private BlockVector3 getInChunkPos(BlockVector3 location) {
return BlockVector3.at(location.getX() & 15, location.getY(), location.getZ() & 15);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
if (!enabled) {
return getExtent().setBlock(location, block);
return setDelegateBlock(location, block);
}
BlockVector2 chunkPos = BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4);
batches.computeIfAbsent(chunkPos, k -> new LocatedBlockList()).add(location, block);
BlockVector2 chunkPos = getChunkPos(location);
BlockVector3 inChunkPos = getInChunkPos(location);
batches.put(chunkPos, inChunkPos, block.toBaseBlock());
containedBlocks.add(location);
return true;
}
@Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (!containedBlocks.contains(position)) {
return Optional.empty();
}
return Optional.of(batches.get(getChunkPos(position), getInChunkPos(position)));
}
@Override
protected Operation commitBefore() {
if (!commitRequired()) {
@ -94,17 +117,22 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
return new Operation() {
// we get modified between create/resume -- only create this on resume to prevent CME
private Iterator<LocatedBlockList> batchIterator;
private Iterator<Map.Entry<BlockVector2, Map<BlockVector3, BaseBlock>>> batchIterator;
@Override
public Operation resume(RunContext run) throws WorldEditException {
if (batchIterator == null) {
batchIterator = batches.values().iterator();
batchIterator = batches.rowMap().entrySet().iterator();
}
if (!batchIterator.hasNext()) {
return null;
}
new SetLocatedBlocks(getExtent(), batchIterator.next()).resume(run);
Map.Entry<BlockVector2, Map<BlockVector3, BaseBlock>> next = batchIterator.next();
BlockVector3 chunkOffset = next.getKey().toBlockVector3().shl(4);
for (Map.Entry<BlockVector3, BaseBlock> block : next.getValue().entrySet()) {
getExtent().setBlock(block.getKey().add(chunkOffset), block.getValue());
containedBlocks.remove(block.getKey());
}
batchIterator.remove();
return this;
}

View File

@ -20,7 +20,7 @@
package com.sk89q.worldedit.extent.reorder;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.OperationQueue;
@ -36,13 +36,17 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
/**
* Re-orders blocks into several stages.
*/
public class MultiStageReorder extends AbstractDelegateExtent implements ReorderingExtent {
public class MultiStageReorder extends AbstractBufferingExtent implements ReorderingExtent {
private static final Map<BlockType, PlacementPriority> priorityMap = new HashMap<>();
@ -139,6 +143,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL);
}
private final Set<BlockVector3> containedBlocks = new HashSet<>();
private Map<PlacementPriority, LocatedBlockList> stages = new HashMap<>();
private boolean enabled;
@ -212,7 +217,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
if (!enabled) {
return super.setBlock(location, block);
return setDelegateBlock(location, block);
}
BlockState existing = getBlock(location);
@ -240,9 +245,21 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
}
stages.get(priority).add(location, block);
containedBlocks.add(location);
return !existing.equalsFuzzy(block);
}
@Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (!containedBlocks.contains(position)) {
return Optional.empty();
}
return stages.values().stream()
.map(blocks -> blocks.get(position))
.filter(Objects::nonNull)
.findAny();
}
@Override
public Operation commitBefore() {
if (!commitRequired()) {

View File

@ -55,7 +55,9 @@ public class BlockOptimizedHistory extends ArrayListHistory {
if (change instanceof BlockChange) {
BlockChange blockChange = (BlockChange) change;
BlockVector3 position = blockChange.getPosition();
if (!previous.containsLocation(position)) {
previous.add(position, blockChange.getPrevious());
}
current.add(position, blockChange.getCurrent());
} else {
super.add(change);

View File

@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
@ -114,11 +115,12 @@ public class ServerCUIHandler {
}
// Borrowed this math from FAWE
double rotX = player.getLocation().getYaw();
double rotY = player.getLocation().getPitch();
final Location location = player.getLocation();
double rotX = location.getYaw();
double rotY = location.getPitch();
double xz = Math.cos(Math.toRadians(rotY));
int x = (int) (player.getLocation().getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12);
int z = (int) (player.getLocation().getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12);
int x = (int) (location.getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12);
int z = (int) (location.getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12);
int y = Math.max(0, Math.min(Math.min(255, posY + 32), posY + 3));
Map<String, Tag> structureTag = new HashMap<>();

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.math;
import com.google.common.collect.ComparisonChain;
import com.sk89q.worldedit.math.transform.AffineTransform;
import java.util.Comparator;
@ -48,12 +47,8 @@ public final class BlockVector2 {
* cdef
* </pre>
*/
public static final Comparator<BlockVector2> COMPARING_GRID_ARRANGEMENT = (a, b) -> {
return ComparisonChain.start()
.compare(a.getBlockZ(), b.getBlockZ())
.compare(a.getBlockX(), b.getBlockX())
.result();
};
public static final Comparator<BlockVector2> COMPARING_GRID_ARRANGEMENT =
Comparator.comparingInt(BlockVector2::getZ).thenComparingInt(BlockVector2::getX);
public static BlockVector2 at(double x, double z) {
return at((int) Math.floor(x), (int) Math.floor(z));
@ -303,6 +298,27 @@ public final class BlockVector2 {
return divide(n, n);
}
/**
* Shift all components right.
*
* @param x the value to shift x by
* @param z the value to shift z by
* @return a new vector
*/
public BlockVector2 shr(int x, int z) {
return at(this.x >> x, this.z >> z);
}
/**
* Shift all components right by {@code n}.
*
* @param n the value to shift by
* @return a new vector
*/
public BlockVector2 shr(int n) {
return shr(n, n);
}
/**
* Get the length of the vector.
*
@ -532,5 +548,4 @@ public final class BlockVector2 {
public String toString() {
return "(" + x + ", " + z + ")";
}
}

View File

@ -19,13 +19,12 @@
package com.sk89q.worldedit.math;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.collect.ComparisonChain;
import com.sk89q.worldedit.math.transform.AffineTransform;
import java.util.Comparator;
import static com.google.common.base.Preconditions.checkArgument;
/**
* An immutable 3-dimensional vector.
*/
@ -64,13 +63,10 @@ public final class BlockVector3 {
// thread-safe initialization idiom
private static final class YzxOrderComparator {
private static final Comparator<BlockVector3> YZX_ORDER = (a, b) -> {
return ComparisonChain.start()
.compare(a.y, b.y)
.compare(a.z, b.z)
.compare(a.x, b.x)
.result();
};
private static final Comparator<BlockVector3> YZX_ORDER =
Comparator.comparingInt(BlockVector3::getY)
.thenComparingInt(BlockVector3::getZ)
.thenComparingInt(BlockVector3::getX);
}
/**
@ -348,6 +344,50 @@ public final class BlockVector3 {
return divide(n, n, n);
}
/**
* Shift all components right.
*
* @param x the value to shift x by
* @param y the value to shift y by
* @param z the value to shift z by
* @return a new vector
*/
public BlockVector3 shr(int x, int y, int z) {
return at(this.x >> x, this.y >> y, this.z >> z);
}
/**
* Shift all components right by {@code n}.
*
* @param n the value to shift by
* @return a new vector
*/
public BlockVector3 shr(int n) {
return shr(n, n, n);
}
/**
* Shift all components left.
*
* @param x the value to shift x by
* @param y the value to shift y by
* @param z the value to shift z by
* @return a new vector
*/
public BlockVector3 shl(int x, int y, int z) {
return at(this.x << x, this.y << y, this.z << z);
}
/**
* Shift all components left by {@code n}.
*
* @param n the value to shift by
* @return a new vector
*/
public BlockVector3 shl(int n) {
return shl(n, n, n);
}
/**
* Get the length of the vector.
*

View File

@ -0,0 +1,41 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit 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.worldedit.scripting;
import org.mozilla.javascript.ClassShutter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Hides Minecraft's obfuscated & de-obfuscated names from scripts.
*/
class MinecraftHidingClassShutter implements ClassShutter {
private static final Logger LOGGER = LoggerFactory.getLogger(MinecraftHidingClassShutter.class);
@Override
public boolean visibleToScripts(String fullClassName) {
if (!fullClassName.contains(".")) {
// Default package -- probably Minecraft
return false;
}
return !fullClassName.startsWith("net.minecraft");
}
}

View File

@ -50,6 +50,7 @@ public class RhinoCraftScriptEngine implements CraftScriptEngine {
throws ScriptException, Throwable {
RhinoContextFactory factory = new RhinoContextFactory(timeLimit);
Context cx = factory.enterContext();
cx.setClassShutter(new MinecraftHidingClassShutter());
ScriptableObject scriptable = new ImporterTopLevel(cx);
Scriptable scope = cx.initStandardObjects(scriptable);

View File

@ -1,134 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit 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.worldedit.scripting.java;
import com.sk89q.worldedit.scripting.RhinoContextFactory;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import java.io.IOException;
import java.io.Reader;
import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
public class RhinoScriptEngine extends AbstractScriptEngine {
private ScriptEngineFactory factory;
private Context cx;
public RhinoScriptEngine() {
RhinoContextFactory factory = new RhinoContextFactory(3000);
factory.enterContext();
}
@Override
public Bindings createBindings() {
return new SimpleBindings();
}
@Override
public Object eval(String script, ScriptContext context)
throws ScriptException {
Scriptable scope = setupScope(cx, context);
String filename = (filename = (String) get(ScriptEngine.FILENAME)) == null
? "<unknown>" : filename;
try {
return cx.evaluateString(scope, script, filename, 1, null);
} catch (RhinoException e) {
String msg;
int line = (line = e.lineNumber()) == 0 ? -1 : line;
if (e instanceof JavaScriptException) {
msg = String.valueOf(((JavaScriptException) e).getValue());
} else {
msg = e.getMessage();
}
ScriptException scriptException =
new ScriptException(msg, e.sourceName(), line);
scriptException.initCause(e);
throw scriptException;
} finally {
Context.exit();
}
}
@Override
public Object eval(Reader reader, ScriptContext context)
throws ScriptException {
Scriptable scope = setupScope(cx, context);
String filename = (filename = (String) get(ScriptEngine.FILENAME)) == null
? "<unknown>" : filename;
try {
return cx.evaluateReader(scope, reader, filename, 1, null);
} catch (RhinoException e) {
String msg;
int line = (line = e.lineNumber()) == 0 ? -1 : line;
if (e instanceof JavaScriptException) {
msg = String.valueOf(((JavaScriptException) e).getValue());
} else {
msg = e.getMessage();
}
ScriptException scriptException =
new ScriptException(msg, e.sourceName(), line);
scriptException.initCause(e);
throw scriptException;
} catch (IOException e) {
throw new ScriptException(e);
} finally {
Context.exit();
}
}
@Override
public ScriptEngineFactory getFactory() {
if (factory != null) {
return factory;
} else {
return new RhinoScriptEngineFactory();
}
}
private Scriptable setupScope(Context cx, ScriptContext context) {
ScriptableObject scriptable = new ImporterTopLevel(cx);
Scriptable scope = cx.initStandardObjects(scriptable);
//ScriptableObject.putProperty(scope, "argv", Context.javaToJS(args, scope));
return scope;
}
}

View File

@ -1,153 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit 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.worldedit.scripting.java;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
public class RhinoScriptEngineFactory implements ScriptEngineFactory {
private static List<String> names;
private static List<String> mimeTypes;
private static List<String> extensions;
static {
names = new ArrayList<>(5);
names.add("ECMAScript");
names.add("ecmascript");
names.add("JavaScript");
names.add("javascript");
names.add("js");
names = Collections.unmodifiableList(names);
mimeTypes = new ArrayList<>(4);
mimeTypes.add("application/ecmascript");
mimeTypes.add("text/ecmascript");
mimeTypes.add("application/javascript");
mimeTypes.add("text/javascript");
mimeTypes = Collections.unmodifiableList(mimeTypes);
extensions = new ArrayList<>(2);
extensions.add("emcascript");
extensions.add("js");
extensions = Collections.unmodifiableList(extensions);
}
@Override
public String getEngineName() {
return "Rhino JavaScript Engine (SK)";
}
@Override
public String getEngineVersion() {
return "unknown";
}
@Override
public List<String> getExtensions() {
return extensions;
}
@Override
public String getLanguageName() {
return "EMCAScript";
}
@Override
public String getLanguageVersion() {
return "1.8";
}
@Override
public String getMethodCallSyntax(String obj, String m, String... args) {
StringBuilder s = new StringBuilder();
s.append(obj);
s.append(".");
s.append(m);
s.append("(");
for (int i = 0; i < args.length; ++i) {
s.append(args[i]);
if (i < args.length - 1) {
s.append(",");
}
}
s.append(")");
return s.toString();
}
@Override
public List<String> getMimeTypes() {
return mimeTypes;
}
@Override
public List<String> getNames() {
return names;
}
@Override
public String getOutputStatement(String str) {
return "print(" + str.replace("\\", "\\\\")
.replace("\"", "\\\\\"")
.replace(";", "\\\\;") + ")";
}
@Override
public Object getParameter(String key) {
switch (key) {
case ScriptEngine.ENGINE:
return getEngineName();
case ScriptEngine.ENGINE_VERSION:
return getEngineVersion();
case ScriptEngine.NAME:
return getEngineName();
case ScriptEngine.LANGUAGE:
return getLanguageName();
case ScriptEngine.LANGUAGE_VERSION:
return getLanguageVersion();
case "THREADING":
return "MULTITHREADED";
default:
throw new IllegalArgumentException("Invalid key");
}
}
@Override
public String getProgram(String... statements) {
StringBuilder s = new StringBuilder();
for (String stmt : statements) {
s.append(stmt);
s.append(";");
}
return s.toString();
}
@Override
public ScriptEngine getScriptEngine() {
return new RhinoScriptEngine();
}
}

View File

@ -21,68 +21,72 @@ package com.sk89q.worldedit.util.collection;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.LocatedBlock;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
/**
* Wrapper around a list of blocks located in the world.
*/
public class LocatedBlockList implements Iterable<LocatedBlock> {
private final List<LocatedBlock> list;
private final Map<BlockVector3, LocatedBlock> map = new LinkedHashMap<>();
public LocatedBlockList() {
list = new ArrayList<>();
}
public LocatedBlockList(Collection<? extends LocatedBlock> collection) {
list = new ArrayList<>(collection);
for (LocatedBlock locatedBlock : collection) {
map.put(locatedBlock.getLocation(), locatedBlock);
}
}
public void add(LocatedBlock setBlockCall) {
checkNotNull(setBlockCall);
list.add(setBlockCall);
map.put(setBlockCall.getLocation(), setBlockCall);
}
public <B extends BlockStateHolder<B>> void add(BlockVector3 location, B block) {
add(new LocatedBlock(location, block.toBaseBlock()));
}
public boolean containsLocation(BlockVector3 location) {
return map.containsKey(location);
}
public @Nullable BaseBlock get(BlockVector3 location) {
return map.get(location).getBlock();
}
public int size() {
return list.size();
return map.size();
}
public void clear() {
list.clear();
map.clear();
}
@Override
public Iterator<LocatedBlock> iterator() {
return list.iterator();
return map.values().iterator();
}
public Iterator<LocatedBlock> reverseIterator() {
return new Iterator<LocatedBlock>() {
private final ListIterator<LocatedBlock> backingIterator = list.listIterator(list.size());
@Override
public boolean hasNext() {
return backingIterator.hasPrevious();
}
@Override
public LocatedBlock next() {
return backingIterator.previous();
}
};
List<LocatedBlock> data = new ArrayList<>(map.values());
Collections.reverse(data);
return data.iterator();
}
}

View File

@ -1,90 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit 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.worldedit.util.formatting.component;
import com.google.common.base.Strings;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import java.util.List;
public class BlockDistributionResult extends PaginationBox {
private final List<Countable<BlockState>> distribution;
private final int totalBlocks;
private final boolean separateStates;
public BlockDistributionResult(List<Countable<BlockState>> distribution, boolean separateStates) {
super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : ""));
this.distribution = distribution;
// note: doing things like region.getArea is inaccurate for non-cuboids.
this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum();
this.separateStates = separateStates;
setComponentsPerPage(7);
}
@Override
public Component getComponent(int number) {
Countable<BlockState> c = distribution.get(number);
TextComponent.Builder line = TextComponent.builder();
final int count = c.getAmount();
final double perc = count / (double) totalBlocks * 100;
final int maxDigits = (int) (Math.log10(totalBlocks) + 1);
final int curDigits = (int) (Math.log10(count) + 1);
line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD);
final int space = maxDigits - curDigits;
String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1);
line.append(String.format("%s%s", count, pad), TextColor.YELLOW);
final BlockState state = c.getID();
final BlockType blockType = state.getBlockType();
TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE);
TextComponent toolTip;
if (separateStates && state != blockType.getDefaultState()) {
toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY);
blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE));
} else {
toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY);
}
blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip));
line.append(blockName);
return line.build();
}
@Override
public int getComponentsSize() {
return distribution.size();
}
@Override
public Component create(int page) throws InvalidComponentException {
super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY))
.append(TextComponent.newline());
return super.create(page);
}
}

View File

@ -32,14 +32,16 @@ public class CommandListBox extends PaginationBox {
private List<CommandEntry> commands = Lists.newArrayList();
private boolean hideHelp;
private String helpCommand;
/**
* Create a new box.
*
* @param title the title
*/
public CommandListBox(String title, String pageCommand) {
public CommandListBox(String title, String pageCommand, String helpCommand) {
super(title, pageCommand);
this.helpCommand = helpCommand;
}
@Override
@ -72,7 +74,7 @@ public class CommandListBox extends PaginationBox {
this.hideHelp = hideHelp;
}
private static class CommandEntry {
private class CommandEntry {
private final String alias;
private final Component description;
private final String insertion;
@ -87,7 +89,7 @@ public class CommandListBox extends PaginationBox {
TextComponentProducer line = new TextComponentProducer();
if (!hideHelp) {
line.append(SubtleFormat.wrap("? ")
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//help " + insertion))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, CommandListBox.this.helpCommand + " " + insertion))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help"))));
}
TextComponent command = TextComponent.of(alias, TextColor.GOLD);

View File

@ -45,9 +45,10 @@ public class CommandUsageBox extends TextComponentProducer {
*
* @param commands the commands to describe
* @param commandString the commands that were used, such as "/we" or "/brush sphere"
* @param helpRootCommand the command used to get subcommand help
*/
public CommandUsageBox(List<Command> commands, String commandString) throws InvalidComponentException {
this(commands, commandString, null);
public CommandUsageBox(List<Command> commands, String commandString, String helpRootCommand) throws InvalidComponentException {
this(commands, commandString, helpRootCommand, null);
}
/**
@ -55,15 +56,18 @@ public class CommandUsageBox extends TextComponentProducer {
*
* @param commands the commands to describe
* @param commandString the commands that were used, such as "/we" or "/brush sphere"
* @param helpRootCommand the command used to get subcommand help
* @param parameters list of parameters to use
*/
public CommandUsageBox(List<Command> commands, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException {
public CommandUsageBox(List<Command> commands, String commandString, String helpRootCommand,
@Nullable CommandParameters parameters) throws InvalidComponentException {
checkNotNull(commands);
checkNotNull(commandString);
attachCommandUsage(commands, commandString);
checkNotNull(helpRootCommand);
attachCommandUsage(commands, commandString, helpRootCommand);
}
private void attachCommandUsage(List<Command> commands, String commandString) {
private void attachCommandUsage(List<Command> commands, String commandString, String helpRootCommand) {
TextComponentProducer boxContent = new TextComponentProducer()
.append(HelpGenerator.create(commands).getFullHelp());
if (getSubCommands(Iterables.getLast(commands)).size() > 0) {
@ -73,7 +77,7 @@ public class CommandUsageBox extends TextComponentProducer {
.append(TextComponent.builder("List Subcommands")
.color(ColorConfig.getMainText())
.decoration(TextDecoration.ITALIC, true)
.clickEvent(ClickEvent.runCommand("//help -s " + commandString))
.clickEvent(ClickEvent.runCommand(helpRootCommand + " -s " + commandString))
.hoverEvent(HoverEvent.showText(TextComponent.of("List all subcommands of this command")))
.build())
.build());

View File

@ -1,75 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit 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.worldedit.util.formatting.component;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
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;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import java.io.File;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
public class SchematicPaginationBox extends PaginationBox {
private final String prefix;
private final File[] files;
public SchematicPaginationBox(String rootDir, File[] files, String pageCommand) {
super("Available schematics", pageCommand);
this.prefix = rootDir == null ? "" : rootDir;
this.files = files;
}
@Override
public Component getComponent(int number) {
checkArgument(number < files.length && number >= 0);
File file = files[number];
Multimap<String, ClipboardFormat> exts = ClipboardFormats.getFileExtensionMap();
String format = exts.get(Files.getFileExtension(file.getName()))
.stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown");
boolean inRoot = file.getParentFile().getName().equals(prefix);
String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1];
return TextComponent.builder()
.content("")
.append(TextComponent.of("[L]")
.color(TextColor.GOLD)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load"))))
.append(TextComponent.space())
.append(TextComponent.of(path)
.color(TextColor.DARK_GREEN)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format))))
.build();
}
@Override
public int getComponentsSize() {
return files.length;
}
}

View File

@ -19,8 +19,9 @@
package com.sk89q.worldedit.util.paste;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.sk89q.worldedit.util.net.HttpRequest;
import org.json.simple.JSONValue;
import java.io.IOException;
import java.net.URL;
@ -33,6 +34,8 @@ public class EngineHubPaste implements Paster {
private static final Pattern URL_PATTERN = Pattern.compile("https?://.+$");
private static final Gson GSON = new Gson();
@Override
public Callable<URL> paste(String content) {
return new PasteTask(content);
@ -59,10 +62,10 @@ public class EngineHubPaste implements Paster {
.returnContent()
.asString("UTF-8").trim();
Object object = JSONValue.parse(result);
if (object instanceof Map) {
@SuppressWarnings("unchecked")
String urlString = String.valueOf(((Map<Object, Object>) object).get("url"));
Map<Object, Object> object = GSON.fromJson(result, new TypeToken<Map<Object, Object>>() {
}.getType());
if (object != null) {
String urlString = String.valueOf(object.get("url"));
Matcher m = URL_PATTERN.matcher(urlString);
if (m.matches()) {

View File

@ -19,19 +19,20 @@
package com.sk89q.minecraft.util.commands;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashSet;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class CommandContextTest {
@ -39,7 +40,7 @@ public class CommandContextTest {
private static final String firstCmdString = "herpderp -opw testers \"mani world\" 'another thing' because something";
CommandContext firstCommand;
@Before
@BeforeEach
public void setUpTest() {
try {
firstCommand = new CommandContext(firstCmdString, new HashSet<>(Arrays.asList('o', 'w')));
@ -49,10 +50,12 @@ public class CommandContextTest {
}
}
@Test(expected = CommandException.class)
public void testInvalidFlags() throws CommandException {
@Test
public void testInvalidFlags() {
final String failingCommand = "herpderp -opw testers";
assertThrows(CommandException.class, () -> {
new CommandContext(failingCommand, new HashSet<>(Arrays.asList('o', 'w')));
});
}
@Test

View File

@ -19,33 +19,33 @@
package com.sk89q.worldedit.extent.transform;
import static org.junit.Assert.assertEquals;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.Set;
@Ignore("A platform is currently required to get properties, preventing this test.")
import static org.junit.jupiter.api.Assertions.assertEquals;
@Disabled("A platform is currently required to get properties, preventing this test.")
public class BlockTransformExtentTest {
private static final Transform ROTATE_90 = new AffineTransform().rotateY(-90);
private static final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90);
private final Set<BlockType> ignored = new HashSet<>();
@Before
public void setUp() throws Exception {
@BeforeEach
public void setUp() {
BlockType.REGISTRY.register("worldedit:test", new BlockType("worldedit:test"));
}
@Test
public void testTransform() throws Exception {
public void testTransform() {
for (BlockType type : BlockType.REGISTRY.values()) {
if (ignored.contains(type)) {
continue;

View File

@ -21,10 +21,10 @@ package com.sk89q.worldedit.internal.command;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.internal.util.Substring;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static com.sk89q.worldedit.internal.command.CommandArgParser.spaceSplit;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CommandArgParserTest {
@Test

View File

@ -19,16 +19,6 @@
package com.sk89q.worldedit.internal.expression;
import static java.lang.Math.atan2;
import static java.lang.Math.sin;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Platform;
@ -36,9 +26,20 @@ import com.sk89q.worldedit.internal.expression.lexer.LexerException;
import com.sk89q.worldedit.internal.expression.parser.ParserException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static java.lang.Math.atan2;
import static java.lang.Math.sin;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ExpressionTest {
@Before
@BeforeEach
public void setup() {
Platform mockPlat = Mockito.mock(Platform.class);
Mockito.when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() {
@ -68,56 +69,46 @@ public class ExpressionTest {
}
@Test
public void testErrors() throws ExpressionException {
public void testErrors() {
assertAll(
// test lexer errors
try {
compile("#");
fail("Error expected");
} catch (LexerException e) {
assertEquals("Error position", 0, e.getPosition());
}
() -> {
LexerException e = assertThrows(LexerException.class,
() -> compile("#"));
assertEquals(0, e.getPosition(), "Error position");
},
// test parser errors
try {
compile("x");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
try {
compile("x()");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
try {
compile("(");
fail("Error expected");
} catch (ParserException ignored) {}
try {
compile("x(");
fail("Error expected");
} catch (ParserException ignored) {}
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("x"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("x()"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> assertThrows(ParserException.class,
() -> compile("(")),
() -> assertThrows(ParserException.class,
() -> compile("x(")),
// test overloader errors
try {
compile("atan2(1)");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
try {
compile("atan2(1, 2, 3)");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
try {
compile("rotate(1, 2, 3)");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("atan2(1)"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("atan2(1, 2, 3)"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("rotate(1, 2, 3)"));
assertEquals(0, e.getPosition(), "Error position");
}
);
}
@Test
@ -181,14 +172,12 @@ public class ExpressionTest {
}
@Test
public void testTimeout() throws Exception {
try {
simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}");
fail("Loop was not stopped.");
} catch (EvaluationException e) {
public void testTimeout() {
ExpressionTimeoutException e = assertThrows(ExpressionTimeoutException.class,
() -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"),
"Loop was not stopped.");
assertTrue(e.getMessage().contains("Calculations exceeded time limit"));
}
}
private double simpleEval(String expressionString) throws ExpressionException {
final Expression expression = compile(expressionString);

View File

@ -19,12 +19,12 @@
package com.sk89q.worldedit.util;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.world.World;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
/**
* Tests {@link Location}.

View File

@ -19,14 +19,14 @@
package com.sk89q.worldedit.util.eventbus;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class EventBusTest {

View File

@ -1,105 +0,0 @@
import net.fabricmc.loom.task.RemapJarTask
buildscript {
repositories {
jcenter()
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
maven {
name = 'sponge'
url = 'https://repo.spongepowered.org/maven'
}
}
dependencies {
classpath 'net.fabricmc:fabric-loom:0.2.4-SNAPSHOT'
classpath 'org.spongepowered:mixin:0.7.11-SNAPSHOT'
}
}
apply plugin: 'eclipse'
apply plugin: 'fabric-loom'
def minecraftVersion = "1.14.3"
def fabricVersion = "0.3.0+build.187"
def yarnMappings = "1.14.3+build.1"
def loaderVersion = "0.4.8+build.155"
configurations.all { Configuration it ->
it.resolutionStrategy { ResolutionStrategy rs ->
rs.force("com.google.guava:guava:21.0")
}
}
dependencies {
compile project(':worldedit-core')
compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'
minecraft "com.mojang:minecraft:${minecraftVersion}"
mappings "net.fabricmc:yarn:${yarnMappings}"
modCompile "net.fabricmc:fabric-loader:${loaderVersion}"
modCompile "net.fabricmc.fabric-api:fabric-api:${fabricVersion}"
testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
minecraft {
}
project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}"
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property 'version', project.internalVersion
from(sourceSets.main.resources.srcDirs) {
include "fabric.mod.json"
expand "version": project.internalVersion
}
// copy everything else except the mod json
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
}
jar {
manifest {
attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version": version)
}
}
shadowJar {
classifier = 'dist-dev'
dependencies {
relocate "org.slf4j", "com.sk89q.worldedit.slf4j"
relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge"
include(dependency('org.slf4j:slf4j-api'))
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
}
}
task deobfJar(type: Jar) {
from sourceSets.main.output
classifier = 'dev'
}
artifacts {
archives deobfJar
}
task shadowJarRemap(type: RemapJarTask) {
input shadowJar.archivePath
output new File(shadowJar.archivePath.getAbsolutePath().replaceFirst('-dev\\.jar$', ".jar"))
}
shadowJarRemap.dependsOn(shadowJar)
build.dependsOn(shadowJarRemap)

View File

@ -0,0 +1,113 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import net.fabricmc.loom.task.RemapJarTask
import kotlin.reflect.KClass
buildscript {
repositories {
jcenter()
maven {
name = "Fabric"
url = uri("https://maven.fabricmc.net/")
}
maven {
name = "sponge"
url = uri("https://repo.spongepowered.org/maven")
}
}
dependencies {
"classpath"("net.fabricmc:fabric-loom:0.2.3-SNAPSHOT")
"classpath"("org.spongepowered:mixin:0.7.11-SNAPSHOT")
}
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
apply(plugin = "fabric-loom")
val minecraftVersion = "1.14.4"
val fabricVersion = "0.3.0+build.200"
val yarnMappings = "1.14.4+build.1"
val loaderVersion = "0.4.8+build.155"
configurations.all {
resolutionStrategy {
force("com.google.guava:guava:21.0")
}
}
dependencies {
"compile"(project(":worldedit-core"))
"compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1")
"minecraft"("com.mojang:minecraft:$minecraftVersion")
"mappings"("net.fabricmc:yarn:$yarnMappings")
"modCompile"("net.fabricmc:fabric-loader:$loaderVersion")
"modCompile"("net.fabricmc.fabric-api:fabric-api:$fabricVersion")
"testCompile"("org.mockito:mockito-core:1.9.0-rc1")
}
configure<BasePluginConvention> {
archivesBaseName = "$archivesBaseName-mc$minecraftVersion"
}
tasks.named<Copy>("processResources") {
// this will ensure that this task is redone when the versions change.
inputs.property("version", project.ext["internalVersion"])
from(sourceSets["main"].resources.srcDirs) {
include("fabric.mod.json")
expand("version" to project.ext["internalVersion"])
}
// copy everything else except the mod json
from(sourceSets["main"].resources.srcDirs) {
exclude("fabric.mod.json")
}
}
tasks.named<Jar>("jar") {
manifest {
attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("shadowJar") {
archiveClassifier.set("dist-dev")
dependencies {
relocate("org.slf4j", "com.sk89q.worldedit.slf4j")
relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge")
include(dependency("org.slf4j:slf4j-api"))
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
}
}
tasks.register<Jar>("deobfJar") {
from(sourceSets["main"].output)
archiveClassifier.set("dev")
}
artifacts {
add("archives", tasks.named("deobfJar"))
}
// intellij has trouble detecting RemapJarTask as a subclass of Task
@Suppress("UNCHECKED_CAST")
val remapJarIntellijHack = RemapJarTask::class as KClass<Task>
tasks.register("remapShadowJar", remapJarIntellijHack) {
(this as RemapJarTask).run {
val shadowJar = tasks.getByName<ShadowJar>("shadowJar")
dependsOn(shadowJar)
setInput(shadowJar.archiveFile)
setOutput(shadowJar.archiveFile.get().asFile.absolutePath.replace(Regex("-dev\\.jar$"), ".jar"))
}
}
tasks.named("assemble").configure {
dependsOn("remapShadowJar")
}

View File

@ -106,7 +106,7 @@ public class FabricPlayer extends AbstractPlayerActor {
}
@Override
public com.sk89q.worldedit.world.World getWorld() {
public World getWorld() {
return FabricWorldEdit.inst.getWorld(this.player.world);
}
@ -188,6 +188,19 @@ public class FabricPlayer extends AbstractPlayerActor {
return null;
}
@Override
public boolean isAllowedToFly() {
return player.abilities.allowFlying;
}
@Override
public void setFlying(boolean flying) {
if (player.abilities.flying != flying) {
player.abilities.flying = flying;
player.sendAbilitiesUpdate();
}
}
@Override
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
World world = getWorld();

View File

@ -202,16 +202,25 @@ public class FabricWorld extends AbstractWorld {
CompoundTag tag = ((BaseBlock) block).getNbtData();
if (tag != null) {
net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag);
nativeTag.putString("id", ((BaseBlock) block).getNbtId());
TileEntityUtils.setTileEntity(world, position, nativeTag);
BlockEntity tileEntity = getWorld().getWorldChunk(pos).getBlockEntity(pos);
if (tileEntity != null) {
tileEntity.fromTag(nativeTag);
tileEntity.setPos(pos);
tileEntity.setWorld(world);
successful = true; // update if TE changed as well
}
}
}
}
if (successful && notifyAndLight) {
world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos);
world.scheduleBlockRender(pos, old, newState);
world.updateListeners(pos, old, newState, UPDATE | NOTIFY);
world.updateNeighbors(pos, newState.getBlock());
if (old.hasComparatorOutput()) {
world.updateHorizontalAdjacent(pos, newState.getBlock());
}
}
return successful;
@ -220,7 +229,9 @@ public class FabricWorld extends AbstractWorld {
@Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ());
getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), getWorld().getBlockState(pos), 1 | 2);
net.minecraft.block.BlockState state = getWorld().getBlockState(pos);
getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), state, 1 | 2);
getWorld().updateNeighbors(pos, state.getBlock());
return true;
}
@ -496,7 +507,9 @@ public class FabricWorld extends AbstractWorld {
BlockEntity tile = ((WorldChunk) getWorld().getChunk(pos)).getBlockEntity(pos, WorldChunk.CreationType.CHECK);
if (tile != null) {
return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile)));
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
tile.toTag(tag);
return getBlock(position).toBaseBlock(NBTConverter.fromNative(tag));
} else {
return getBlock(position).toBaseBlock();
}

View File

@ -1,79 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit 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.worldedit.fabric;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.math.BlockVector3;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntTag;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nullable;
/**
* Utility methods for setting tile entities in the world.
*/
final class TileEntityUtils {
private TileEntityUtils() {
}
/**
* Update the given tag compound with position information.
*
* @param tag the tag
* @param position the position
*/
private static void updateForSet(CompoundTag tag, BlockVector3 position) {
checkNotNull(tag);
checkNotNull(position);
tag.put("x", new IntTag(position.getBlockX()));
tag.put("y", new IntTag(position.getBlockY()));
tag.put("z", new IntTag(position.getBlockZ()));
}
/**
* Set a tile entity at the given location using the tile entity ID from
* the tag.
*
* @param world the world
* @param position the position
* @param tag the tag for the tile entity (may be null to do nothing)
*/
static void setTileEntity(World world, BlockVector3 position, @Nullable CompoundTag tag) {
if (tag != null) {
updateForSet(tag, position);
BlockEntity tileEntity = BlockEntity.createFromTag(tag);
if (tileEntity != null) {
world.setBlockEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity);
}
}
}
public static CompoundTag copyNbtData(BlockEntity tile) {
CompoundTag tag = new CompoundTag();
tile.toTag(tag);
return tag;
}
}

View File

@ -1,115 +0,0 @@
buildscript {
repositories {
mavenLocal()
mavenCentral()
maven { url = "https://files.minecraftforge.net/maven" }
jcenter()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
}
}
apply plugin: 'eclipse'
apply plugin: 'net.minecraftforge.gradle'
def minecraftVersion = "1.14.3"
def forgeVersion = "27.0.13"
configurations.all { Configuration it ->
it.resolutionStrategy { ResolutionStrategy rs ->
rs.force("com.google.guava:guava:21.0")
}
}
dependencies {
compile project(':worldedit-core')
compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2'
minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}"
testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
minecraft {
mappings channel: 'snapshot', version: "20190626-${minecraftVersion}"
runs {
client = {
// recommended logging data for a userdev environment
properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP'
// recommended logging level for the console
properties 'forge.logging.console.level': 'debug'
workingDirectory project.file('run').canonicalPath
source sourceSets.main
}
server = {
// recommended logging data for a userdev environment
properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP'
// recommended logging level for the console
properties 'forge.logging.console.level': 'debug'
workingDirectory project.file('run').canonicalPath
source sourceSets.main
}
}
}
project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}"
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property 'version', project.internalVersion
inputs.property 'forgeVersion', forgeVersion
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'META-INF/mods.toml'
// replace version and mcversion
expand 'version': project.internalVersion, 'forgeVersion': forgeVersion
}
// copy everything else except the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'META-INF/mods.toml'
}
}
jar {
manifest {
attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version": version)
}
}
shadowJar {
dependencies {
relocate "org.slf4j", "com.sk89q.worldedit.slf4j"
relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge"
include(dependency('org.slf4j:slf4j-api'))
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
}
}
afterEvaluate {
reobf {
shadowJar {
mappings = createMcpToSrg.output
}
}
}
task deobfJar(type: Jar) {
from sourceSets.main.output
classifier = 'dev'
}
artifacts {
archives deobfJar
}

View File

@ -0,0 +1,113 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import net.minecraftforge.gradle.common.util.RunConfig
import net.minecraftforge.gradle.userdev.UserDevExtension
import net.minecraftforge.gradle.userdev.tasks.GenerateSRG
import net.minecraftforge.gradle.userdev.tasks.RenameJarInPlace
plugins {
id("net.minecraftforge.gradle")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
val minecraftVersion = "1.14.4"
val mappingsMinecraftVersion = "1.14.3"
val forgeVersion = "28.0.16"
configurations.all {
resolutionStrategy {
force("com.google.guava:guava:21.0")
}
}
dependencies {
"compile"(project(":worldedit-core"))
"compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.11.2")
"minecraft"("net.minecraftforge:forge:$minecraftVersion-$forgeVersion")
}
configure<UserDevExtension> {
mappings(mapOf(
"channel" to "snapshot",
"version" to "20190724-$mappingsMinecraftVersion"
))
runs {
val runConfig = Action<RunConfig> {
properties(mapOf(
"forge.logging.markers" to "SCAN,REGISTRIES,REGISTRYDUMP",
"forge.logging.console.level" to "debug"
))
workingDirectory = project.file("run").canonicalPath
source(sourceSets["main"])
}
create("client", runConfig)
create("server", runConfig)
}
}
configure<BasePluginConvention> {
archivesBaseName = "$archivesBaseName-mc$minecraftVersion"
}
tasks.named<Copy>("processResources") {
// this will ensure that this task is redone when the versions change.
inputs.property("version", project.ext["internalVersion"])
inputs.property("forgeVersion", forgeVersion)
// replace stuff in mcmod.info, nothing else
from(sourceSets["main"].resources.srcDirs) {
include("META-INF/mods.toml")
// replace version and mcversion
expand(
"version" to project.ext["internalVersion"],
"forgeVersion" to forgeVersion
)
}
// copy everything else except the mcmod.info
from(sourceSets["main"].resources.srcDirs) {
exclude("META-INF/mods.toml")
}
}
tasks.named<Jar>("jar") {
manifest {
attributes("WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("shadowJar") {
dependencies {
relocate("org.slf4j", "com.sk89q.worldedit.slf4j")
relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge")
include(dependency("org.slf4j:slf4j-api"))
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
include(dependency("de.schlichtherle:truezip"))
include(dependency("org.mozilla:rhino"))
}
minimize {
exclude(dependency("org.mozilla:rhino"))
}
}
afterEvaluate {
val reobf = extensions.getByName<NamedDomainObjectContainer<RenameJarInPlace>>("reobf")
reobf.maybeCreate("shadowJar").run {
mappings = tasks.getByName<GenerateSRG>("createMcpToSrg").output
}
}
tasks.register<Jar>("deobfJar") {
from(sourceSets["main"].output)
archiveClassifier.set("dev")
}
artifacts {
add("archives", tasks.named("deobfJar"))
}

View File

@ -35,7 +35,7 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.PlayerList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SharedConstants;
import net.minecraft.world.ServerWorld;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager;

View File

@ -107,7 +107,7 @@ public class ForgePlayer extends AbstractPlayerActor {
}
@Override
public com.sk89q.worldedit.world.World getWorld() {
public World getWorld() {
return ForgeWorldEdit.inst.getWorld(this.player.world);
}
@ -189,6 +189,19 @@ public class ForgePlayer extends AbstractPlayerActor {
return null;
}
@Override
public boolean isAllowedToFly() {
return player.abilities.allowFlying;
}
@Override
public void setFlying(boolean flying) {
if (player.abilities.isFlying != flying) {
player.abilities.isFlying = flying;
player.sendPlayerAbilities();
}
}
@Override
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
World world = getWorld();

View File

@ -65,13 +65,11 @@ import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.ServerWorld;
import net.minecraft.world.World;
import net.minecraft.world.chunk.AbstractChunkProvider;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.chunk.ServerChunkProvider;
import net.minecraft.world.chunk.listener.IChunkStatusListener;
import net.minecraft.world.gen.feature.BigBrownMushroomFeature;
import net.minecraft.world.gen.feature.BigMushroomFeatureConfig;
@ -91,11 +89,14 @@ import net.minecraft.world.gen.feature.ShrubFeature;
import net.minecraft.world.gen.feature.SwampTreeFeature;
import net.minecraft.world.gen.feature.TallTaigaTreeFeature;
import net.minecraft.world.gen.feature.TreeFeature;
import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.SaveHandler;
import net.minecraft.world.storage.WorldInfo;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.file.Path;
import java.util.Collections;
@ -329,8 +330,8 @@ public class ForgeWorld extends AbstractWorld {
MinecraftServer server = originalWorld.getServer();
SaveHandler saveHandler = new SaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer());
World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(),
originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener());
try (World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(),
originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener())) {
// Pre-gen all the chunks
// We need to also pull one more chunk in every direction
@ -343,6 +344,9 @@ public class ForgeWorld extends AbstractWorld {
for (BlockVector3 vec : region) {
editSession.setBlock(vec, from.getFullBlock(vec));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} catch (MaxChangedBlocksException e) {
throw new RuntimeException(e);
} finally {
@ -579,15 +583,15 @@ public class ForgeWorld extends AbstractWorld {
private static class NoOpChunkStatusListener implements IChunkStatusListener {
@Override
public void func_219509_a(ChunkPos chunkPos) {
public void start(ChunkPos chunkPos) {
}
@Override
public void func_219508_a(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) {
public void statusChanged(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) {
}
@Override
public void func_219510_b() {
public void stop() {
}
}
}

View File

@ -21,7 +21,7 @@ package com.sk89q.worldedit.forge;
import com.mojang.authlib.GameProfile;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.world.ServerWorld;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.util.FakePlayer;
import javax.annotation.Nullable;

View File

@ -22,13 +22,8 @@ package com.sk89q.worldedit.forge.net.handler;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.forge.ForgePlayer;
import com.sk89q.worldedit.forge.ForgeWorldEdit;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.ThreadQuickExitException;
import net.minecraft.network.play.server.SCustomPayloadPlayPacket;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.network.NetworkEvent.ClientCustomPayloadEvent;
import net.minecraftforge.fml.network.NetworkEvent.ServerCustomPayloadEvent;
import net.minecraftforge.fml.network.event.EventNetworkChannel;
import java.nio.charset.Charset;
@ -47,10 +42,9 @@ public final class WECUIPacketHandler {
public static void init() {
HANDLER.addListener(WECUIPacketHandler::onPacketData);
HANDLER.addListener(WECUIPacketHandler::callProcessPacket);
}
public static void onPacketData(ServerCustomPayloadEvent event) {
public static void onPacketData(ClientCustomPayloadEvent event) {
ServerPlayerEntity player = event.getSource().get().getSender();
LocalSession session = ForgeWorldEdit.inst.getSession(player);
@ -64,14 +58,4 @@ public final class WECUIPacketHandler {
session.describeCUI(actor);
}
public static void callProcessPacket(ClientCustomPayloadEvent event) {
try {
new SCustomPayloadPlayPacket(
new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL),
event.getPayload()
).processPacket(Minecraft.getInstance().player.connection);
} catch (ThreadQuickExitException ignored) {
}
}
}

9
worldedit-libs/README.md Normal file
View File

@ -0,0 +1,9 @@
This project shades _API_ libraries, i.e. those libraries
whose classes are publicly referenced from `-core` classes.
This project _does not_ shade implementation libraries, i.e.
those libraries whose classes are internally depended on.
This is because the main reason for shading those libraries is for
their internal usage in each platform, not because we need them available to
dependents of `-core` to compile and work with WorldEdit's API.

View File

@ -1,143 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
/*
This project shades <em>API</em> libraries, i.e. those libraries
whose classes are publicly referenced from `-core` classes.
This project <em>does not</em> shade implementation libraries, i.e.
those libraries whose classes are internally depended on.
This is because the main reason for shading those libraries is for
their internal usage in each platform, not because we need them available to
dependents of `-core` to compile and work with WorldEdit's API.
*/
configure(subprojects + project("core:ap")) {
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 + ".worldedit-libs"
tasks.register("jar", ShadowJar) {
configurations = [project.configurations.shade]
classifier = ""
dependencies {
exclude(dependency("com.google.guava:guava"))
exclude(dependency("com.google.code.gson:gson"))
exclude(dependency("org.checkerframework:checker-qual"))
}
relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text')
}
def altConfigFiles = { String artifactType ->
def deps = configurations.shade.incoming.dependencies
.collect { it.copy() }
.collect { dependency ->
dependency.artifact { artifact ->
artifact.name = dependency.name
artifact.type = artifactType
artifact.extension = 'jar'
artifact.classifier = artifactType
}
dependency
}
return files(configurations.detachedConfiguration(deps as Dependency[])
.resolvedConfiguration.lenientConfiguration.getArtifacts()
.findAll { it.classifier == artifactType }
.collect { zipTree(it.file) })
}
tasks.register("sourcesJar", Jar) {
from {
altConfigFiles('sources')
}
def filePattern = ~'(.*)net/kyori/text((?:/|$).*)'
def textPattern = ~/net\.kyori\.text/
eachFile {
it.filter { String line ->
line.replaceFirst(textPattern, 'com.sk89q.worldedit.util.formatting.text')
}
it.path = it.path.replaceFirst(filePattern, '$1com/sk89q/worldedit/util/formatting/text$2')
}
classifier = "sources"
}
artifacts {
add("default", jar)
add("archives", sourcesJar)
}
tasks.register("install", Upload) {
configuration = configurations.archives
repositories.mavenInstaller {
pom.version = project.version
pom.artifactId = project.name
}
}
artifactoryPublish {
publishConfigs('default')
}
build.dependsOn(jar, sourcesJar)
}
def textExtrasVersion = "3.0.2"
project("core") {
def textVersion = "3.0.1"
def pistonVersion = '0.4.2'
dependencies {
shade "net.kyori:text-api:$textVersion"
shade "net.kyori:text-serializer-gson:$textVersion"
shade "net.kyori:text-serializer-legacy:$textVersion"
shade "net.kyori:text-serializer-plain:$textVersion"
shade('com.sk89q:jchronic:0.2.4a') {
exclude(group: "junit", module: "junit")
}
shade 'com.thoughtworks.paranamer:paranamer:2.6'
shade 'com.sk89q.lib:jlibnoise:1.0.0'
shade "org.enginehub.piston:core:$pistonVersion"
shade "org.enginehub.piston.core-ap:runtime:$pistonVersion"
shade "org.enginehub.piston:default-impl:$pistonVersion"
}
project("ap") {
dependencies {
shade "org.enginehub.piston.core-ap:annotations:$pistonVersion"
shade "org.enginehub.piston.core-ap:processor:$pistonVersion"
}
}
}
project("bukkit") {
repositories {
maven {
name = "SpigotMC"
url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/"
}
}
dependencies {
shade "net.kyori:text-adapter-bukkit:$textExtrasVersion"
}
}
project("sponge") {
repositories {
maven {
name = "Sponge"
url = "https://repo.spongepowered.org/maven"
}
}
dependencies {
shade "net.kyori:text-adapter-spongeapi:$textExtrasVersion"
}
}
tasks.register("build") {
dependsOn(subprojects.collect { it.tasks.named("build") })
}

View File

@ -0,0 +1,3 @@
tasks.register("build") {
dependsOn(subprojects.map { it.tasks.named("build") })
}

View File

@ -0,0 +1,11 @@
applyLibrariesConfiguration()
repositories {
maven {
name = "SpigotMC"
url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
}
}
dependencies {
"shade"("net.kyori:text-adapter-bukkit:${Versions.TEXT_EXTRAS}")
}

View File

@ -0,0 +1,6 @@
applyLibrariesConfiguration()
dependencies {
"shade"("org.enginehub.piston.core-ap:annotations:${Versions.PISTON}")
"shade"("org.enginehub.piston.core-ap:processor:${Versions.PISTON}")
}

View File

@ -0,0 +1,16 @@
applyLibrariesConfiguration()
dependencies {
"shade"("net.kyori:text-api:${Versions.TEXT}")
"shade"("net.kyori:text-serializer-gson:${Versions.TEXT}")
"shade"("net.kyori:text-serializer-legacy:${Versions.TEXT}")
"shade"("net.kyori:text-serializer-plain:${Versions.TEXT}")
"shade"("com.sk89q:jchronic:0.2.4a") {
exclude(group = "junit", module = "junit")
}
"shade"("com.thoughtworks.paranamer:paranamer:2.6")
"shade"("com.sk89q.lib:jlibnoise:1.0.0")
"shade"("org.enginehub.piston:core:${Versions.PISTON}")
"shade"("org.enginehub.piston.core-ap:runtime:${Versions.PISTON}")
"shade"("org.enginehub.piston:default-impl:${Versions.PISTON}")
}

View File

@ -0,0 +1 @@
applyLibrariesConfiguration()

View File

@ -0,0 +1 @@
applyLibrariesConfiguration()

View File

@ -0,0 +1,11 @@
applyLibrariesConfiguration()
repositories {
maven {
name = "Sponge"
url = uri("https://repo.spongepowered.org/maven")
}
}
dependencies {
"shade"("net.kyori:text-adapter-spongeapi:${Versions.TEXT_EXTRAS}")
}

View File

@ -1,58 +0,0 @@
buildscript {
repositories {
mavenCentral()
maven { url = "https://files.minecraftforge.net/maven" }
maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" }
jcenter()
}
}
plugins {
id 'org.spongepowered.plugin' version '0.9.0'
}
repositories {
maven { url "https://repo.codemc.org/repository/maven-public" }
}
dependencies {
compile project(':worldedit-core')
compile project(':worldedit-libs:sponge')
compile 'org.spongepowered:spongeapi:7.1.0'
compile 'org.bstats:bstats-sponge:1.5'
testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1'
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sponge {
plugin {
id = 'worldedit'
}
}
jar {
manifest {
attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version": version)
}
}
shadowJar {
dependencies {
relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") {
include(dependency('org.bstats:bstats-sponge:1.5'))
}
}
}
if (project.hasProperty("signing")) {
apply plugin: 'signing'
signing {
sign shadowJar
}
build.dependsOn('signShadowJar')
}

View File

@ -0,0 +1,53 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
id("org.spongepowered.plugin")
}
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
repositories {
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
}
dependencies {
compile(project(":worldedit-core"))
compile(project(":worldedit-libs:sponge"))
compile("org.spongepowered:spongeapi:7.1.0")
compile("org.bstats:bstats-sponge:1.5")
testCompile("org.mockito:mockito-core:1.9.0-rc1")
}
sponge {
plugin {
id = "worldedit"
}
}
tasks.named<Jar>("jar") {
manifest {
attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar",
"WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("shadowJar") {
dependencies {
relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") {
include(dependency("org.bstats:bstats-sponge:1.5"))
}
}
}
if (project.hasProperty("signing")) {
apply(plugin = "signing")
configure<SigningExtension> {
sign("shadowJar")
}
tasks.named("build").configure {
dependsOn("signShadowJar")
}
}

View File

@ -38,6 +38,7 @@ import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
import com.sk89q.worldedit.world.item.ItemTypes;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.data.type.HandTypes;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.item.ItemType;
@ -202,6 +203,16 @@ public class SpongePlayer extends AbstractPlayerActor {
gameMode.getId()).get());
}
@Override
public boolean isAllowedToFly() {
return player.get(Keys.CAN_FLY).orElse(super.isAllowedToFly());
}
@Override
public void setFlying(boolean flying) {
player.offer(Keys.IS_FLYING, flying);
}
@Override
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
org.spongepowered.api.world.Location<World> loc = player.getWorld().getLocation(pos.getX(), pos.getY(), pos.getZ());